Merge "Improve Accessibility behaviour in recents" into mnc-dev
diff --git a/Android.mk b/Android.mk
index bd8b16a..b71f08c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -197,6 +197,7 @@
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
+	core/java/android/os/IDeviceIdleController.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
diff --git a/api/current.txt b/api/current.txt
index b419064..c2ea905 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23,8 +23,10 @@
     field public static final java.lang.String BIND_CARRIER_CONFIG_SERVICE = "android.permission.BIND_CARRIER_CONFIG_SERVICE";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
+    field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_MEDIA_ROUTE_SERVICE = "android.permission.BIND_MEDIA_ROUTE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
@@ -278,7 +280,7 @@
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
-    field public static final int allowUndo = 16844006; // 0x10104e6
+    field public static final int allowUndo = 16844005; // 0x10104e5
     field public static final int alpha = 16843551; // 0x101031f
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
@@ -299,7 +301,7 @@
     field public static final int anyDensity = 16843372; // 0x101026c
     field public static final int apduServiceBanner = 16843757; // 0x10103ed
     field public static final int apiKey = 16843281; // 0x1010211
-    field public static final int assistBlocked = 16844020; // 0x10104f4
+    field public static final int assistBlocked = 16844019; // 0x10104f3
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -310,7 +312,7 @@
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
-    field public static final int autoVerify = 16844010; // 0x10104ea
+    field public static final int autoVerify = 16844009; // 0x10104e9
     field public static final int background = 16842964; // 0x10100d4
     field public static final int backgroundDimAmount = 16842802; // 0x1010032
     field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -334,7 +336,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
-    field public static final int breakStrategy = 16844011; // 0x10104eb
+    field public static final int breakStrategy = 16844010; // 0x10104ea
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -396,7 +398,7 @@
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
-    field public static final int colorBackgroundFloating = 16844007; // 0x10104e7
+    field public static final int colorBackgroundFloating = 16844006; // 0x10104e6
     field public static final int colorButtonNormal = 16843819; // 0x101042b
     field public static final int colorControlActivated = 16843818; // 0x101042a
     field public static final int colorControlHighlight = 16843820; // 0x101042c
@@ -505,7 +507,7 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
-    field public static final int dynamicResources = 16844019; // 0x10104f3
+    field public static final int dynamicResources = 16844018; // 0x10104f2
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
@@ -517,7 +519,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
-    field public static final int end = 16843997; // 0x10104dd
+    field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -539,7 +541,7 @@
     field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
     field public static final int exported = 16842768; // 0x1010010
     field public static final int extraTension = 16843371; // 0x101026b
-    field public static final int extractNativeLibs = 16844008; // 0x10104e8
+    field public static final int extractNativeLibs = 16844007; // 0x10104e7
     field public static final int factor = 16843219; // 0x10101d3
     field public static final int fadeDuration = 16843384; // 0x1010278
     field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -653,8 +655,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
-    field public static final int iconTint = 16844000; // 0x10104e0
-    field public static final int iconTintMode = 16844001; // 0x10104e1
+    field public static final int iconTint = 16843999; // 0x10104df
+    field public static final int iconTintMode = 16844000; // 0x10104e0
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -794,7 +796,7 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
-    field public static final int leftIndents = 16844016; // 0x10104f0
+    field public static final int leftIndents = 16844015; // 0x10104ef
     field public static final int letterSpacing = 16843958; // 0x10104b6
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -817,7 +819,7 @@
     field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
     field public static final int listViewStyle = 16842868; // 0x1010074
     field public static final int listViewWhiteStyle = 16842869; // 0x1010075
-    field public static final int lockTaskMode = 16844015; // 0x10104ef
+    field public static final int lockTaskMode = 16844014; // 0x10104ee
     field public static final int logo = 16843454; // 0x10102be
     field public static final int longClickable = 16842982; // 0x10100e6
     field public static final int loopViews = 16843527; // 0x1010307
@@ -866,8 +868,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
-    field public static final int navigationTint = 16844004; // 0x10104e4
-    field public static final int navigationTintMode = 16844005; // 0x10104e5
+    field public static final int navigationTint = 16844003; // 0x10104e3
+    field public static final int navigationTintMode = 16844004; // 0x10104e4
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -881,7 +883,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
-    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
+    field public static final int numbersInnerTextColor = 16843998; // 0x10104de
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -899,8 +901,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
-    field public static final int overflowTint = 16844002; // 0x10104e2
-    field public static final int overflowTintMode = 16844003; // 0x10104e3
+    field public static final int overflowTint = 16844001; // 0x10104e1
+    field public static final int overflowTintMode = 16844002; // 0x10104e2
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -995,7 +997,7 @@
     field public static final int readPermission = 16842759; // 0x1010007
     field public static final int recognitionService = 16843932; // 0x101049c
     field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
-    field public static final int removeBeforeMRelease = 16844014; // 0x10104ee
+    field public static final int removeBeforeMRelease = 16844013; // 0x10104ed
     field public static final int reparent = 16843964; // 0x10104bc
     field public static final int reparentWithOverlay = 16843965; // 0x10104bd
     field public static final int repeatCount = 16843199; // 0x10101bf
@@ -1014,7 +1016,6 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
-    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1024,7 +1025,7 @@
     field public static final int reversible = 16843851; // 0x101044b
     field public static final int revisionCode = 16843989; // 0x10104d5
     field public static final int right = 16843183; // 0x10101af
-    field public static final int rightIndents = 16844017; // 0x10104f1
+    field public static final int rightIndents = 16844016; // 0x10104f0
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
@@ -1100,7 +1101,7 @@
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
-    field public static final int showForAllUsers = 16844018; // 0x10104f2
+    field public static final int showForAllUsers = 16844017; // 0x10104f1
     field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
@@ -1130,7 +1131,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
-    field public static final int start = 16843996; // 0x10104dc
+    field public static final int start = 16843995; // 0x10104db
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1172,6 +1173,7 @@
     field public static final int strokeLineJoin = 16843788; // 0x101040c
     field public static final int strokeMiterLimit = 16843789; // 0x101040d
     field public static final int strokeWidth = 16843783; // 0x1010407
+    field public static final int stylusButtonPressable = 16844020; // 0x10104f4
     field public static final int submitBackground = 16843912; // 0x1010488
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -1186,7 +1188,7 @@
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
-    field public static final int supportsAssistGesture = 16844012; // 0x10104ec
+    field public static final int supportsAssistGesture = 16844011; // 0x10104eb
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1287,7 +1289,7 @@
     field public static final int thicknessRatio = 16843164; // 0x101019c
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
-    field public static final int thumbPosition = 16844013; // 0x10104ed
+    field public static final int thumbPosition = 16844012; // 0x10104ec
     field public static final int thumbTextPadding = 16843634; // 0x1010372
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
@@ -1351,7 +1353,7 @@
     field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
     field public static final int useLevel = 16843167; // 0x101019f
     field public static final int userVisible = 16843409; // 0x1010291
-    field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
+    field public static final int usesCleartextTraffic = 16844008; // 0x10104e8
     field public static final int value = 16842788; // 0x1010024
     field public static final int valueFrom = 16843486; // 0x10102de
     field public static final int valueTo = 16843487; // 0x10102df
@@ -1416,10 +1418,10 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
-    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
+    field public static final int windowLightStatusBar = 16843997; // 0x10104dd
     field public static final int windowMinWidthMajor = 16843606; // 0x1010356
     field public static final int windowMinWidthMinor = 16843607; // 0x1010357
     field public static final int windowNoDisplay = 16843294; // 0x101021e
@@ -1685,6 +1687,7 @@
     ctor public R.id();
     field public static final int accessibilityActionScrollToPosition = 16908342; // 0x1020036
     field public static final int accessibilityActionShowOnScreen = 16908341; // 0x1020035
+    field public static final int accessibilityActionStylusButtonPress = 16908344; // 0x1020038
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
@@ -2732,7 +2735,6 @@
   }
 
   public class AccountManager {
-    method public boolean accountAuthenticated(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2756,6 +2758,7 @@
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
+    method public boolean notifyAccountAuthenticated(android.accounts.Account);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -2793,7 +2796,7 @@
     field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
     field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
     field public static final java.lang.String KEY_INTENT = "intent";
-    field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
+    field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -4078,6 +4081,7 @@
     method public boolean isFocused();
     method public boolean isLongClickable();
     method public boolean isSelected();
+    method public boolean isStylusButtonPressable();
     field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
     field public static final int TEXT_STYLE_BOLD = 1; // 0x1
     field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
@@ -4324,9 +4328,11 @@
     method public boolean getAllowReturnTransitionOverlap();
     method public final android.os.Bundle getArguments();
     method public final android.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context getContext();
     method public android.transition.Transition getEnterTransition();
     method public android.transition.Transition getExitTransition();
     method public final android.app.FragmentManager getFragmentManager();
+    method public final java.lang.Object getHost();
     method public final int getId();
     method public android.app.LoaderManager getLoaderManager();
     method public final android.app.Fragment getParentFragment();
@@ -4356,7 +4362,8 @@
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
-    method public void onAttach(android.app.Activity);
+    method public void onAttach(android.content.Context);
+    method public deprecated void onAttach(android.app.Activity);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public boolean onContextItemSelected(android.view.MenuItem);
     method public void onCreate(android.os.Bundle);
@@ -4370,7 +4377,8 @@
     method public void onDetach();
     method public void onHiddenChanged(boolean);
     method public deprecated void onInflate(android.util.AttributeSet, android.os.Bundle);
-    method public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
@@ -4437,6 +4445,64 @@
     method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
   }
 
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method public abstract android.view.View onFindViewById(int);
+    method public abstract boolean onHasView();
+  }
+
+  public class FragmentController {
+    method public void attachHost(android.app.Fragment);
+    method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method public void dispatchTrimMemory(int);
+    method public void doLoaderDestroy();
+    method public void doLoaderStart();
+    method public void doLoaderStop(boolean);
+    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public boolean execPendingActions();
+    method public android.app.Fragment findFragmentByWho(java.lang.String);
+    method public android.app.FragmentManager getFragmentManager();
+    method public android.app.LoaderManager getLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public void reportLoaderStart();
+    method public void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>);
+    method public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String, android.app.LoaderManager>);
+    method public android.util.ArrayMap<java.lang.String, android.app.LoaderManager> retainLoaderNonConfig();
+    method public java.util.List<android.app.Fragment> retainNonConfig();
+    method public android.os.Parcelable saveAllState();
+  }
+
+  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.view.View onFindViewById(int);
+    method public abstract E onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method public void onInvalidateOptionsMenu();
+    method public boolean onShouldSaveFragmentState(android.app.Fragment);
+    method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public boolean onUseFragmentManagerInflaterFactory();
+  }
+
   public abstract class FragmentManager {
     ctor public FragmentManager();
     method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
@@ -5729,6 +5795,7 @@
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public int getPermissionPolicy(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
@@ -5781,6 +5848,8 @@
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
+    method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean);
+    method public void setPermissionPolicy(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setPreferredSetupActivity(android.content.ComponentName, android.content.ComponentName);
@@ -5869,6 +5938,9 @@
     field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000
     field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000
     field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0
+    field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
+    field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
+    field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
@@ -9402,6 +9474,7 @@
     field public static final int GET_SIGNATURES = 64; // 0x40
     field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
+    field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
@@ -13226,6 +13299,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
@@ -13909,7 +13983,9 @@
   public static class FingerprintManager.CryptoObject {
     ctor public FingerprintManager.CryptoObject(java.security.Signature);
     ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);
     method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
     method public java.security.Signature getSignature();
   }
 
@@ -14016,6 +14092,7 @@
     method public java.lang.String getProductName();
     method public java.lang.String getSerialNumber();
     method public int getVendorId();
+    method public java.lang.String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR;
   }
@@ -17257,6 +17334,7 @@
     field public static final java.lang.String PROPERTY_PRODUCT = "product";
     field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
     field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
     field public static final int TYPE_BLUETOOTH = 3; // 0x3
     field public static final int TYPE_USB = 1; // 0x1
     field public static final int TYPE_VIRTUAL = 2; // 0x2
@@ -18360,6 +18438,7 @@
     method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
     method public void onLosing(android.net.Network, int);
     method public void onLost(android.net.Network);
+    method public void onPreCheck(android.net.Network);
   }
 
   public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -27085,7 +27164,8 @@
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final java.lang.String APN = "apn";
     field public static final java.lang.String AUTH_TYPE = "authtype";
-    field public static final java.lang.String BEARER = "bearer";
+    field public static final deprecated java.lang.String BEARER = "bearer";
+    field public static final java.lang.String BEARER_BITMASK = "bearer_bitmask";
     field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String CURRENT = "current";
@@ -28158,36 +28238,102 @@
 
   public final class ScriptIntrinsicBLAS extends android.renderscript.ScriptIntrinsic {
     method public void BNNM(android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation, int, int);
+    method public void CGBMV(int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
     method public void CGEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
-    method public void CHEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void CGEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CGERC(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CGERU(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHBMV(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
+    method public void CHEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHER(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHER2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void CHER2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
     method public void CHERK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void CHPMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHPR2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void CSYMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
     method public void CSYR2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
-    method public void CSYRK(int, int, float, float, android.renderscript.Allocation, float, float, android.renderscript.Allocation);
+    method public void CSYRK(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
+    method public void CTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void CTRMM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void CTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void CTRSM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void CTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DGBMV(int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
     method public void DGEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DGEMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DGER(double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSBMV(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSPMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSPR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void DSYMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DSYMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSYR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSYR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void DSYR2K(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
     method public void DSYRK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void DTRMM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void DTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void DTRSM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void DTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void SGBMV(int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
     method public void SGEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void SGEMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SGER(float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSBMV(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSPMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSPR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void SSYMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void SSYMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSYR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSYR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void SSYR2K(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
     method public void SSYRK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void STBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void STRMM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void STRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void STRSM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void STRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZGBMV(int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
     method public void ZGEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
-    method public void ZHEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void ZGEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZGERC(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZGERU(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHBMV(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
+    method public void ZHEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHER(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHER2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void ZHER2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
     method public void ZHERK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void ZHPMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHPR2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void ZSYMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
     method public void ZSYR2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
-    method public void ZSYRK(int, int, double, double, android.renderscript.Allocation, double, double, android.renderscript.Allocation);
+    method public void ZSYRK(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
+    method public void ZTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void ZTRMM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void ZTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void ZTRSM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void ZTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public static android.renderscript.ScriptIntrinsicBLAS create(android.renderscript.RenderScript);
     field public static final int CONJ_TRANSPOSE = 113; // 0x71
     field public static final int LEFT = 141; // 0x8d
@@ -28526,10 +28672,9 @@
     method public java.lang.String getKeystoreAlias();
     method public int getPurposes();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static class KeyGeneratorSpec.Builder {
@@ -28539,7 +28684,6 @@
     method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
     method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -28547,8 +28691,8 @@
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
     method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
     method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int);
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -28576,10 +28720,9 @@
     method public java.util.Date getStartDate();
     method public javax.security.auth.x500.X500Principal getSubjectDN();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static final class KeyPairGeneratorSpec.Builder {
@@ -28592,7 +28735,6 @@
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
     method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
@@ -28605,8 +28747,14 @@
     method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
     method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
+    ctor public KeyPermanentlyInvalidatedException();
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String);
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class KeyStoreKeyProperties {
@@ -28631,14 +28779,6 @@
   public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation {
   }
 
-  public static abstract class KeyStoreKeyProperties.UserAuthenticator {
-    field public static final int FINGERPRINT_READER = 2; // 0x2
-    field public static final int LOCK_SCREEN = 1; // 0x1
-  }
-
-  public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation {
-  }
-
   public class KeyStoreKeySpec implements java.security.spec.KeySpec {
     method public java.lang.String[] getBlockModes();
     method public java.lang.String[] getDigests();
@@ -28651,15 +28791,15 @@
     method public int getOrigin();
     method public int getPurposes();
     method public java.lang.String[] getSignaturePaddings();
-    method public int getTeeEnforcedUserAuthenticators();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isTeeBacked();
+    method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationRequirementTeeEnforced();
   }
 
   public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
     method public java.lang.String[] getBlockModes();
+    method public android.content.Context getContext();
     method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getKeyValidityForConsumptionEnd();
@@ -28668,11 +28808,10 @@
     method public int getPurposes();
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isDigestsSpecified();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static final class KeyStoreParameter.Builder {
@@ -28682,7 +28821,6 @@
     method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -28690,8 +28828,8 @@
     method public android.security.KeyStoreParameter.Builder setPurposes(int);
     method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int);
   }
 
   public class NetworkSecurityPolicy {
@@ -28699,11 +28837,6 @@
     method public boolean isCleartextTrafficPermitted();
   }
 
-  public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
-    ctor public NewFingerprintEnrolledException();
-    ctor public NewFingerprintEnrolledException(java.lang.String);
-  }
-
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
     ctor public UserNotAuthenticatedException();
     ctor public UserNotAuthenticatedException(java.lang.String);
@@ -29206,6 +29339,7 @@
     field public static final java.lang.String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
     field public static final java.lang.String EXTRA_ORIGIN = "android.speech.extra.ORIGIN";
     field public static final java.lang.String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
+    field public static final java.lang.String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
     field public static final java.lang.String EXTRA_PROMPT = "android.speech.extra.PROMPT";
     field public static final java.lang.String EXTRA_RESULTS = "android.speech.extra.RESULTS";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
@@ -30125,6 +30259,7 @@
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
     method public void registerCallback(android.telecom.Call.Callback);
+    method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
     method public void splitFromConference();
     method public void stopDtmfTone();
@@ -30432,7 +30567,7 @@
   public static abstract class InCallService.VideoCall {
     ctor public InCallService.VideoCall();
     method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback);
-    method public abstract void unregisterCallback();
+    method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback, android.os.Handler);
     method public abstract void requestCallDataUsage();
     method public abstract void requestCameraCapabilities();
     method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile);
@@ -30443,6 +30578,7 @@
     method public abstract void setPauseImage(java.lang.String);
     method public abstract void setPreviewSurface(android.view.Surface);
     method public abstract void setZoom(float);
+    method public abstract void unregisterCallback(android.telecom.InCallService.VideoCall.Callback);
   }
 
   public static abstract class InCallService.VideoCall.Callback {
@@ -30530,6 +30666,7 @@
     method public void merge();
     method public void playDtmfTone(char);
     method public final void registerCallback(android.telecom.RemoteConference.Callback);
+    method public final void registerCallback(android.telecom.RemoteConference.Callback, android.os.Handler);
     method public void separate(android.telecom.RemoteConnection);
     method public void setAudioState(android.telecom.AudioState);
     method public void stopDtmfTone();
@@ -30569,6 +30706,7 @@
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
+    method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
     method public void setAudioState(android.telecom.AudioState);
     method public void stopDtmfTone();
@@ -30687,11 +30825,34 @@
     method public android.os.Bundle getConfigForSubId(int);
     method public void reloadCarrierConfigForSubId(int);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    field public static final java.lang.String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+    field public static final java.lang.String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
     field public static final java.lang.String BOOL_APN_EXPAND = "bool_apn_expand";
+    field public static final java.lang.String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
+    field public static final java.lang.String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+    field public static final java.lang.String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+    field public static final java.lang.String BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+    field public static final java.lang.String BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
+    field public static final java.lang.String BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+    field public static final java.lang.String BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
+    field public static final java.lang.String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+    field public static final java.lang.String BOOL_PREFER_2G = "bool_prefer_2g";
     field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String BOOL_SHOW_CDMA = "bool_show_cdma";
+    field public static final java.lang.String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+    field public static final java.lang.String BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+    field public static final java.lang.String BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+    field public static final java.lang.String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+    field public static final java.lang.String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+    field public static final java.lang.String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+    field public static final java.lang.String BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+    field public static final java.lang.String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+    field public static final java.lang.String BOOL_WORLD_PHONE = "bool_world_phone";
     field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
   }
 
@@ -33997,6 +34158,7 @@
     method public static void readEvents(int[], java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
     method public static int writeEvent(int, int);
     method public static int writeEvent(int, long);
+    method public static int writeEvent(int, float);
     method public static int writeEvent(int, java.lang.String);
     method public static int writeEvent(int, java.lang.Object...);
   }
@@ -34783,6 +34945,7 @@
     field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
+    field public static final int STYLUS_BUTTON_PRESS = 6; // 0x6
     field public static final int VIRTUAL_KEY = 1; // 0x1
   }
 
@@ -35515,6 +35678,7 @@
     method public final float getY(int);
     method public final float getYPrecision();
     method public final boolean isButtonPressed(int);
+    method public final boolean isStylusButtonPressed();
     method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int);
     method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
     method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
@@ -36119,6 +36283,7 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public boolean isStylusButtonPressable();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
@@ -36186,6 +36351,7 @@
     method public boolean performHapticFeedback(int);
     method public boolean performHapticFeedback(int, int);
     method public boolean performLongClick();
+    method public boolean performStylusButtonPress();
     method public void playSoundEffect(int);
     method public boolean post(java.lang.Runnable);
     method public boolean postDelayed(java.lang.Runnable, long);
@@ -36289,6 +36455,7 @@
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(android.view.View.OnLongClickListener);
     method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
+    method public void setOnStylusButtonPressListener(android.view.View.OnStylusButtonPressListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
     method public void setOutlineProvider(android.view.ViewOutlineProvider);
@@ -36317,6 +36484,7 @@
     method public void setSelected(boolean);
     method public void setSoundEffectsEnabled(boolean);
     method public void setStateListAnimator(android.animation.StateListAnimator);
+    method public void setStylusButtonPressable(boolean);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
     method public void setTag(int, java.lang.Object);
@@ -36564,6 +36732,10 @@
     method public abstract void onScrollChange(android.view.View, int, int, int, int);
   }
 
+  public static abstract interface View.OnStylusButtonPressListener {
+    method public abstract boolean onStylusButtonPress(android.view.View);
+  }
+
   public static abstract interface View.OnSystemUiVisibilityChangeListener {
     method public abstract void onSystemUiVisibilityChange(int);
   }
@@ -36605,6 +36777,7 @@
     method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
     method public abstract void setLongClickable(boolean);
     method public abstract void setSelected(boolean);
+    method public abstract void setStylusButtonPressable(boolean);
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
@@ -37490,6 +37663,7 @@
     field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2
     field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
     field public static final int TYPE_VIEW_SELECTED = 4; // 0x4
+    field public static final int TYPE_VIEW_STYLUS_BUTTON_PRESSED = 8388608; // 0x800000
     field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
     field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
     field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
@@ -37580,6 +37754,7 @@
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isStylusButtonPressable();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -37630,6 +37805,7 @@
     method public void setSelected(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
+    method public void setStylusButtonPressable(boolean);
     method public void setText(java.lang.CharSequence);
     method public void setTextSelection(int, int);
     method public void setTraversalAfter(android.view.View);
@@ -37707,6 +37883,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_STYLUS_BUTTON_PRESS;
   }
 
   public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9df8b98..f5212a3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -351,7 +351,7 @@
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
-    field public static final int allowUndo = 16844006; // 0x10104e6
+    field public static final int allowUndo = 16844005; // 0x10104e5
     field public static final int alpha = 16843551; // 0x101031f
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
@@ -372,7 +372,7 @@
     field public static final int anyDensity = 16843372; // 0x101026c
     field public static final int apduServiceBanner = 16843757; // 0x10103ed
     field public static final int apiKey = 16843281; // 0x1010211
-    field public static final int assistBlocked = 16844020; // 0x10104f4
+    field public static final int assistBlocked = 16844019; // 0x10104f3
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -383,7 +383,7 @@
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
-    field public static final int autoVerify = 16844010; // 0x10104ea
+    field public static final int autoVerify = 16844009; // 0x10104e9
     field public static final int background = 16842964; // 0x10100d4
     field public static final int backgroundDimAmount = 16842802; // 0x1010032
     field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -407,7 +407,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
-    field public static final int breakStrategy = 16844011; // 0x10104eb
+    field public static final int breakStrategy = 16844010; // 0x10104ea
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -469,7 +469,7 @@
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
-    field public static final int colorBackgroundFloating = 16844007; // 0x10104e7
+    field public static final int colorBackgroundFloating = 16844006; // 0x10104e6
     field public static final int colorButtonNormal = 16843819; // 0x101042b
     field public static final int colorControlActivated = 16843818; // 0x101042a
     field public static final int colorControlHighlight = 16843820; // 0x101042c
@@ -578,7 +578,7 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
-    field public static final int dynamicResources = 16844019; // 0x10104f3
+    field public static final int dynamicResources = 16844018; // 0x10104f2
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
@@ -590,7 +590,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
-    field public static final int end = 16843997; // 0x10104dd
+    field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -612,7 +612,7 @@
     field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
     field public static final int exported = 16842768; // 0x1010010
     field public static final int extraTension = 16843371; // 0x101026b
-    field public static final int extractNativeLibs = 16844008; // 0x10104e8
+    field public static final int extractNativeLibs = 16844007; // 0x10104e7
     field public static final int factor = 16843219; // 0x10101d3
     field public static final int fadeDuration = 16843384; // 0x1010278
     field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -726,8 +726,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
-    field public static final int iconTint = 16844000; // 0x10104e0
-    field public static final int iconTintMode = 16844001; // 0x10104e1
+    field public static final int iconTint = 16843999; // 0x10104df
+    field public static final int iconTintMode = 16844000; // 0x10104e0
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -867,7 +867,7 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
-    field public static final int leftIndents = 16844016; // 0x10104f0
+    field public static final int leftIndents = 16844015; // 0x10104ef
     field public static final int letterSpacing = 16843958; // 0x10104b6
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -890,7 +890,7 @@
     field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
     field public static final int listViewStyle = 16842868; // 0x1010074
     field public static final int listViewWhiteStyle = 16842869; // 0x1010075
-    field public static final int lockTaskMode = 16844015; // 0x10104ef
+    field public static final int lockTaskMode = 16844014; // 0x10104ee
     field public static final int logo = 16843454; // 0x10102be
     field public static final int longClickable = 16842982; // 0x10100e6
     field public static final int loopViews = 16843527; // 0x1010307
@@ -939,8 +939,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
-    field public static final int navigationTint = 16844004; // 0x10104e4
-    field public static final int navigationTintMode = 16844005; // 0x10104e5
+    field public static final int navigationTint = 16844003; // 0x10104e3
+    field public static final int navigationTintMode = 16844004; // 0x10104e4
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -954,7 +954,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
-    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
+    field public static final int numbersInnerTextColor = 16843998; // 0x10104de
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -972,8 +972,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
-    field public static final int overflowTint = 16844002; // 0x10104e2
-    field public static final int overflowTintMode = 16844003; // 0x10104e3
+    field public static final int overflowTint = 16844001; // 0x10104e1
+    field public static final int overflowTintMode = 16844002; // 0x10104e2
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -1068,7 +1068,7 @@
     field public static final int readPermission = 16842759; // 0x1010007
     field public static final int recognitionService = 16843932; // 0x101049c
     field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
-    field public static final int removeBeforeMRelease = 16844014; // 0x10104ee
+    field public static final int removeBeforeMRelease = 16844013; // 0x10104ed
     field public static final int reparent = 16843964; // 0x10104bc
     field public static final int reparentWithOverlay = 16843965; // 0x10104bd
     field public static final int repeatCount = 16843199; // 0x10101bf
@@ -1087,7 +1087,6 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
-    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1097,7 +1096,7 @@
     field public static final int reversible = 16843851; // 0x101044b
     field public static final int revisionCode = 16843989; // 0x10104d5
     field public static final int right = 16843183; // 0x10101af
-    field public static final int rightIndents = 16844017; // 0x10104f1
+    field public static final int rightIndents = 16844016; // 0x10104f0
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
@@ -1177,7 +1176,7 @@
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
-    field public static final int showForAllUsers = 16844018; // 0x10104f2
+    field public static final int showForAllUsers = 16844017; // 0x10104f1
     field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
@@ -1207,7 +1206,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
-    field public static final int start = 16843996; // 0x10104dc
+    field public static final int start = 16843995; // 0x10104db
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1249,6 +1248,7 @@
     field public static final int strokeLineJoin = 16843788; // 0x101040c
     field public static final int strokeMiterLimit = 16843789; // 0x101040d
     field public static final int strokeWidth = 16843783; // 0x1010407
+    field public static final int stylusButtonPressable = 16844020; // 0x10104f4
     field public static final int submitBackground = 16843912; // 0x1010488
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -1263,7 +1263,7 @@
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
-    field public static final int supportsAssistGesture = 16844012; // 0x10104ec
+    field public static final int supportsAssistGesture = 16844011; // 0x10104eb
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1364,7 +1364,7 @@
     field public static final int thicknessRatio = 16843164; // 0x101019c
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
-    field public static final int thumbPosition = 16844013; // 0x10104ed
+    field public static final int thumbPosition = 16844012; // 0x10104ec
     field public static final int thumbTextPadding = 16843634; // 0x1010372
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
@@ -1428,7 +1428,7 @@
     field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
     field public static final int useLevel = 16843167; // 0x101019f
     field public static final int userVisible = 16843409; // 0x1010291
-    field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
+    field public static final int usesCleartextTraffic = 16844008; // 0x10104e8
     field public static final int value = 16842788; // 0x1010024
     field public static final int valueFrom = 16843486; // 0x10102de
     field public static final int valueTo = 16843487; // 0x10102df
@@ -1493,10 +1493,10 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
-    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
+    field public static final int windowLightStatusBar = 16843997; // 0x10104dd
     field public static final int windowMinWidthMajor = 16843606; // 0x1010356
     field public static final int windowMinWidthMinor = 16843607; // 0x1010357
     field public static final int windowNoDisplay = 16843294; // 0x101021e
@@ -1762,6 +1762,7 @@
     ctor public R.id();
     field public static final int accessibilityActionScrollToPosition = 16908342; // 0x1020036
     field public static final int accessibilityActionShowOnScreen = 16908341; // 0x1020035
+    field public static final int accessibilityActionStylusButtonPress = 16908344; // 0x1020038
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
@@ -2812,7 +2813,6 @@
   }
 
   public class AccountManager {
-    method public boolean accountAuthenticated(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2836,6 +2836,7 @@
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
+    method public boolean notifyAccountAuthenticated(android.accounts.Account);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -2873,7 +2874,7 @@
     field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
     field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
     field public static final java.lang.String KEY_INTENT = "intent";
-    field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
+    field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -3950,6 +3951,7 @@
     method public void finishOp(java.lang.String, int, java.lang.String);
     method public int noteOp(java.lang.String, int, java.lang.String);
     method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+    method public static java.lang.String permissionToOp(java.lang.String);
     method public int startOp(java.lang.String, int, java.lang.String);
     method public int startOpNoThrow(java.lang.String, int, java.lang.String);
     method public void startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
@@ -4169,6 +4171,7 @@
     method public boolean isFocused();
     method public boolean isLongClickable();
     method public boolean isSelected();
+    method public boolean isStylusButtonPressable();
     field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
     field public static final int TEXT_STYLE_BOLD = 1; // 0x1
     field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
@@ -4415,9 +4418,11 @@
     method public boolean getAllowReturnTransitionOverlap();
     method public final android.os.Bundle getArguments();
     method public final android.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context getContext();
     method public android.transition.Transition getEnterTransition();
     method public android.transition.Transition getExitTransition();
     method public final android.app.FragmentManager getFragmentManager();
+    method public final java.lang.Object getHost();
     method public final int getId();
     method public android.app.LoaderManager getLoaderManager();
     method public final android.app.Fragment getParentFragment();
@@ -4447,7 +4452,8 @@
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
-    method public void onAttach(android.app.Activity);
+    method public void onAttach(android.content.Context);
+    method public deprecated void onAttach(android.app.Activity);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public boolean onContextItemSelected(android.view.MenuItem);
     method public void onCreate(android.os.Bundle);
@@ -4461,7 +4467,8 @@
     method public void onDetach();
     method public void onHiddenChanged(boolean);
     method public deprecated void onInflate(android.util.AttributeSet, android.os.Bundle);
-    method public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
@@ -4528,6 +4535,64 @@
     method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
   }
 
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method public abstract android.view.View onFindViewById(int);
+    method public abstract boolean onHasView();
+  }
+
+  public class FragmentController {
+    method public void attachHost(android.app.Fragment);
+    method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method public void dispatchTrimMemory(int);
+    method public void doLoaderDestroy();
+    method public void doLoaderStart();
+    method public void doLoaderStop(boolean);
+    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public boolean execPendingActions();
+    method public android.app.Fragment findFragmentByWho(java.lang.String);
+    method public android.app.FragmentManager getFragmentManager();
+    method public android.app.LoaderManager getLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public void reportLoaderStart();
+    method public void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>);
+    method public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String, android.app.LoaderManager>);
+    method public android.util.ArrayMap<java.lang.String, android.app.LoaderManager> retainLoaderNonConfig();
+    method public java.util.List<android.app.Fragment> retainNonConfig();
+    method public android.os.Parcelable saveAllState();
+  }
+
+  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.view.View onFindViewById(int);
+    method public abstract E onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method public void onInvalidateOptionsMenu();
+    method public boolean onShouldSaveFragmentState(android.app.Fragment);
+    method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public boolean onUseFragmentManagerInflaterFactory();
+  }
+
   public abstract class FragmentManager {
     ctor public FragmentManager();
     method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
@@ -5828,6 +5893,7 @@
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public int getPermissionPolicy(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
@@ -5886,6 +5952,8 @@
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
+    method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean);
+    method public void setPermissionPolicy(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setPreferredSetupActivity(android.content.ComponentName, android.content.ComponentName);
@@ -5979,6 +6047,9 @@
     field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000
     field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000
     field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0
+    field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
+    field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
+    field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
@@ -9697,6 +9768,7 @@
     field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
     field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
     field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+    field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
@@ -13526,6 +13598,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
@@ -14209,7 +14282,9 @@
   public static class FingerprintManager.CryptoObject {
     ctor public FingerprintManager.CryptoObject(java.security.Signature);
     ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);
     method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
     method public java.security.Signature getSignature();
   }
 
@@ -14922,6 +14997,7 @@
     method public java.lang.String getProductName();
     method public java.lang.String getSerialNumber();
     method public int getVendorId();
+    method public java.lang.String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR;
   }
@@ -15464,6 +15540,7 @@
     method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
     method public boolean hasTimeFromLastBitInMs();
+    method public boolean isPseudorangeRateCorrected();
     method public boolean isUsedInFix();
     method public void reset();
     method public void resetAzimuthInDeg();
@@ -15529,6 +15606,7 @@
     field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
     field public static final short STATE_BIT_SYNC = 2; // 0x2
     field public static final short STATE_CODE_LOCK = 1; // 0x1
+    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
     field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
     field public static final short STATE_TOW_DECODED = 8; // 0x8
     field public static final short STATE_UNKNOWN = 0; // 0x0
@@ -15556,6 +15634,7 @@
     method public byte[] getData();
     method public short getMessageId();
     method public byte getPrn();
+    method public short getStatus();
     method public short getSubmessageId();
     method public byte getType();
     method public void reset();
@@ -15563,10 +15642,14 @@
     method public void setData(byte[]);
     method public void setMessageId(short);
     method public void setPrn(byte);
+    method public void setStatus(short);
     method public void setSubmessageId(short);
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final short STATUS_UNKNOWN = 0; // 0x0
     field public static final byte TYPE_CNAV2 = 4; // 0x4
     field public static final byte TYPE_L1CA = 1; // 0x1
     field public static final byte TYPE_L2CNAV = 2; // 0x2
@@ -18544,6 +18627,7 @@
     field public static final java.lang.String PROPERTY_PRODUCT = "product";
     field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
     field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
     field public static final int TYPE_BLUETOOTH = 3; // 0x3
     field public static final int TYPE_USB = 1; // 0x1
     field public static final int TYPE_VIRTUAL = 2; // 0x2
@@ -19822,6 +19906,7 @@
     method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
     method public void onLosing(android.net.Network, int);
     method public void onLost(android.net.Network);
+    method public void onPreCheck(android.net.Network);
   }
 
   public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -29092,7 +29177,8 @@
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final java.lang.String APN = "apn";
     field public static final java.lang.String AUTH_TYPE = "authtype";
-    field public static final java.lang.String BEARER = "bearer";
+    field public static final deprecated java.lang.String BEARER = "bearer";
+    field public static final java.lang.String BEARER_BITMASK = "bearer_bitmask";
     field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String CURRENT = "current";
@@ -30165,36 +30251,102 @@
 
   public final class ScriptIntrinsicBLAS extends android.renderscript.ScriptIntrinsic {
     method public void BNNM(android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation, int, int);
+    method public void CGBMV(int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
     method public void CGEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
-    method public void CHEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void CGEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CGERC(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CGERU(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHBMV(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
+    method public void CHEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHER(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHER2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void CHER2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
     method public void CHERK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void CHPMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int);
+    method public void CHPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void CHPR2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void CSYMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
     method public void CSYR2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
-    method public void CSYRK(int, int, float, float, android.renderscript.Allocation, float, float, android.renderscript.Allocation);
+    method public void CSYRK(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation);
+    method public void CTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void CTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void CTRMM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void CTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void CTRSM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void CTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DGBMV(int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
     method public void DGEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DGEMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DGER(double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSBMV(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSPMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSPR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void DSYMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DSYMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int);
+    method public void DSYR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void DSYR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void DSYR2K(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
     method public void DSYRK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void DTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void DTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void DTRMM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void DTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void DTRSM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void DTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void SGBMV(int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
     method public void SGEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void SGEMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SGER(float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSBMV(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSPMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSPR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void SSYMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void SSYMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int);
+    method public void SSYR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void SSYR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void SSYR2K(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation);
     method public void SSYRK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation);
+    method public void STBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void STPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void STRMM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void STRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void STRSM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void STRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZGBMV(int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
     method public void ZGEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
-    method public void ZHEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void ZGEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZGERC(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZGERU(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHBMV(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
+    method public void ZHEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHER(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHER2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void ZHER2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation);
     method public void ZHERK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation);
+    method public void ZHPMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int);
+    method public void ZHPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation);
+    method public void ZHPR2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation);
     method public void ZSYMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
     method public void ZSYR2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
-    method public void ZSYRK(int, int, double, double, android.renderscript.Allocation, double, double, android.renderscript.Allocation);
+    method public void ZSYRK(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation);
+    method public void ZTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
+    method public void ZTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void ZTRMM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void ZTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public void ZTRSM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void ZTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int);
     method public static android.renderscript.ScriptIntrinsicBLAS create(android.renderscript.RenderScript);
     field public static final int CONJ_TRANSPOSE = 113; // 0x71
     field public static final int LEFT = 141; // 0x8d
@@ -30533,10 +30685,9 @@
     method public java.lang.String getKeystoreAlias();
     method public int getPurposes();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static class KeyGeneratorSpec.Builder {
@@ -30546,7 +30697,6 @@
     method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
     method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -30554,8 +30704,8 @@
     method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
     method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
     method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int);
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -30583,10 +30733,9 @@
     method public java.util.Date getStartDate();
     method public javax.security.auth.x500.X500Principal getSubjectDN();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static final class KeyPairGeneratorSpec.Builder {
@@ -30599,7 +30748,6 @@
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
     method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
     method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
@@ -30612,8 +30760,14 @@
     method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
     method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int);
+  }
+
+  public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
+    ctor public KeyPermanentlyInvalidatedException();
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String);
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class KeyStoreKeyProperties {
@@ -30638,14 +30792,6 @@
   public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation {
   }
 
-  public static abstract class KeyStoreKeyProperties.UserAuthenticator {
-    field public static final int FINGERPRINT_READER = 2; // 0x2
-    field public static final int LOCK_SCREEN = 1; // 0x1
-  }
-
-  public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation {
-  }
-
   public class KeyStoreKeySpec implements java.security.spec.KeySpec {
     method public java.lang.String[] getBlockModes();
     method public java.lang.String[] getDigests();
@@ -30658,15 +30804,15 @@
     method public int getOrigin();
     method public int getPurposes();
     method public java.lang.String[] getSignaturePaddings();
-    method public int getTeeEnforcedUserAuthenticators();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isTeeBacked();
+    method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationRequirementTeeEnforced();
   }
 
   public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
     method public java.lang.String[] getBlockModes();
+    method public android.content.Context getContext();
     method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getKeyValidityForConsumptionEnd();
@@ -30675,11 +30821,10 @@
     method public int getPurposes();
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public int getUserAuthenticators();
     method public boolean isDigestsSpecified();
     method public boolean isEncryptionRequired();
-    method public boolean isInvalidatedOnNewFingerprintEnrolled();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isUserAuthenticationRequired();
   }
 
   public static final class KeyStoreParameter.Builder {
@@ -30689,7 +30834,6 @@
     method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
     method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean);
     method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -30697,8 +30841,8 @@
     method public android.security.KeyStoreParameter.Builder setPurposes(int);
     method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean);
     method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int);
   }
 
   public class NetworkSecurityPolicy {
@@ -30706,11 +30850,6 @@
     method public boolean isCleartextTrafficPermitted();
   }
 
-  public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
-    ctor public NewFingerprintEnrolledException();
-    ctor public NewFingerprintEnrolledException(java.lang.String);
-  }
-
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
     ctor public UserNotAuthenticatedException();
     ctor public UserNotAuthenticatedException(java.lang.String);
@@ -31313,6 +31452,7 @@
     field public static final java.lang.String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
     field public static final java.lang.String EXTRA_ORIGIN = "android.speech.extra.ORIGIN";
     field public static final java.lang.String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
+    field public static final java.lang.String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
     field public static final java.lang.String EXTRA_PROMPT = "android.speech.extra.PROMPT";
     field public static final java.lang.String EXTRA_RESULTS = "android.speech.extra.RESULTS";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
@@ -32233,6 +32373,7 @@
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
     method public void registerCallback(android.telecom.Call.Callback);
+    method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
     method public deprecated void removeListener(android.telecom.Call.Listener);
     method public void splitFromConference();
@@ -32549,7 +32690,7 @@
   public static abstract class InCallService.VideoCall {
     ctor public InCallService.VideoCall();
     method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback);
-    method public abstract void unregisterCallback();
+    method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback, android.os.Handler);
     method public abstract void requestCallDataUsage();
     method public abstract void requestCameraCapabilities();
     method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile);
@@ -32560,6 +32701,7 @@
     method public abstract void setPauseImage(java.lang.String);
     method public abstract void setPreviewSurface(android.view.Surface);
     method public abstract void setZoom(float);
+    method public abstract void unregisterCallback(android.telecom.InCallService.VideoCall.Callback);
   }
 
   public static abstract class InCallService.VideoCall.Callback {
@@ -32667,6 +32809,7 @@
     method public void merge();
     method public void playDtmfTone(char);
     method public final void registerCallback(android.telecom.RemoteConference.Callback);
+    method public final void registerCallback(android.telecom.RemoteConference.Callback, android.os.Handler);
     method public void separate(android.telecom.RemoteConnection);
     method public void setAudioState(android.telecom.AudioState);
     method public void stopDtmfTone();
@@ -32706,6 +32849,7 @@
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
+    method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
     method public void setAudioState(android.telecom.AudioState);
     method public void stopDtmfTone();
@@ -32845,11 +32989,34 @@
     method public void reloadCarrierConfigForSubId(int);
     method public void updateConfigForPhoneId(int, java.lang.String);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    field public static final java.lang.String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+    field public static final java.lang.String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
     field public static final java.lang.String BOOL_APN_EXPAND = "bool_apn_expand";
+    field public static final java.lang.String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
+    field public static final java.lang.String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+    field public static final java.lang.String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+    field public static final java.lang.String BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+    field public static final java.lang.String BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
+    field public static final java.lang.String BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+    field public static final java.lang.String BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
+    field public static final java.lang.String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+    field public static final java.lang.String BOOL_PREFER_2G = "bool_prefer_2g";
     field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String BOOL_SHOW_CDMA = "bool_show_cdma";
+    field public static final java.lang.String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+    field public static final java.lang.String BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+    field public static final java.lang.String BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+    field public static final java.lang.String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+    field public static final java.lang.String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+    field public static final java.lang.String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+    field public static final java.lang.String BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+    field public static final java.lang.String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+    field public static final java.lang.String BOOL_WORLD_PHONE = "bool_world_phone";
     field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
   }
 
@@ -36201,6 +36368,7 @@
     method public static void readEvents(int[], java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
     method public static int writeEvent(int, int);
     method public static int writeEvent(int, long);
+    method public static int writeEvent(int, float);
     method public static int writeEvent(int, java.lang.String);
     method public static int writeEvent(int, java.lang.Object...);
   }
@@ -36987,6 +37155,7 @@
     field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
+    field public static final int STYLUS_BUTTON_PRESS = 6; // 0x6
     field public static final int VIRTUAL_KEY = 1; // 0x1
   }
 
@@ -37719,6 +37888,7 @@
     method public final float getY(int);
     method public final float getYPrecision();
     method public final boolean isButtonPressed(int);
+    method public final boolean isStylusButtonPressed();
     method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int);
     method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
     method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
@@ -38323,6 +38493,7 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public boolean isStylusButtonPressable();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
@@ -38390,6 +38561,7 @@
     method public boolean performHapticFeedback(int);
     method public boolean performHapticFeedback(int, int);
     method public boolean performLongClick();
+    method public boolean performStylusButtonPress();
     method public void playSoundEffect(int);
     method public boolean post(java.lang.Runnable);
     method public boolean postDelayed(java.lang.Runnable, long);
@@ -38493,6 +38665,7 @@
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(android.view.View.OnLongClickListener);
     method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
+    method public void setOnStylusButtonPressListener(android.view.View.OnStylusButtonPressListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
     method public void setOutlineProvider(android.view.ViewOutlineProvider);
@@ -38521,6 +38694,7 @@
     method public void setSelected(boolean);
     method public void setSoundEffectsEnabled(boolean);
     method public void setStateListAnimator(android.animation.StateListAnimator);
+    method public void setStylusButtonPressable(boolean);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
     method public void setTag(int, java.lang.Object);
@@ -38768,6 +38942,10 @@
     method public abstract void onScrollChange(android.view.View, int, int, int, int);
   }
 
+  public static abstract interface View.OnStylusButtonPressListener {
+    method public abstract boolean onStylusButtonPress(android.view.View);
+  }
+
   public static abstract interface View.OnSystemUiVisibilityChangeListener {
     method public abstract void onSystemUiVisibilityChange(int);
   }
@@ -38809,6 +38987,7 @@
     method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
     method public abstract void setLongClickable(boolean);
     method public abstract void setSelected(boolean);
+    method public abstract void setStylusButtonPressable(boolean);
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
@@ -39697,6 +39876,7 @@
     field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2
     field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
     field public static final int TYPE_VIEW_SELECTED = 4; // 0x4
+    field public static final int TYPE_VIEW_STYLUS_BUTTON_PRESSED = 8388608; // 0x800000
     field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
     field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
     field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
@@ -39787,6 +39967,7 @@
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isStylusButtonPressable();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -39837,6 +40018,7 @@
     method public void setSelected(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
+    method public void setStylusButtonPressable(boolean);
     method public void setText(java.lang.CharSequence);
     method public void setTextSelection(int, int);
     method public void setTraversalAfter(android.view.View);
@@ -39914,6 +40096,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_STYLUS_BUTTON_PRESS;
   }
 
   public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 480d171..ffa36d6 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -207,8 +207,7 @@
      * were authenticated successfully. Time is specified in milliseconds since
      * epoch.
      */
-    public static final String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH =
-            "lastAuthenticatedTimeMillisEpoch";
+    public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
 
     /**
      * Authenticators using 'customTokens' option will also get the UID of the
@@ -671,8 +670,8 @@
     }
 
     /**
-     * Informs the system that the account has been authenticated recently. This
-     * recency may be used by other applications to verify the account. This
+     * Notifies the system that the account has just been authenticated. This
+     * information may be used by other applications to verify the account. This
      * should be called only when the user has entered correct credentials for
      * the account.
      * <p>
@@ -685,7 +684,7 @@
      *
      * @param account The {@link Account} to be updated.
      */
-    public boolean accountAuthenticated(Account account) {
+    public boolean notifyAccountAuthenticated(Account account) {
         if (account == null)
             throw new IllegalArgumentException("account is null");
         try {
@@ -1587,7 +1586,7 @@
      * password prompt.
      * 
      * <p>Also the returning Bundle may contain {@link
-     * #KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH} indicating the last time the
+     * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
      * credential was validated/created.
      * 
      * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 69cba78..e79e20c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -108,6 +108,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
@@ -706,8 +707,6 @@
     /*package*/ ActivityThread mMainThread;
     Activity mParent;
     boolean mCalled;
-    boolean mCheckedForLoaderManager;
-    boolean mLoadersStarted;
     /*package*/ boolean mResumed;
     private boolean mStopped;
     boolean mFinished;
@@ -726,8 +725,8 @@
     static final class NonConfigurationInstances {
         Object activity;
         HashMap<String, Object> children;
-        ArrayList<Fragment> fragments;
-        ArrayMap<String, LoaderManagerImpl> loaders;
+        List<Fragment> fragments;
+        ArrayMap<String, LoaderManager> loaders;
         VoiceInteractor voiceInteractor;
     }
     /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
@@ -747,26 +746,13 @@
     private CharSequence mTitle;
     private int mTitleColor = 0;
 
-    final FragmentManagerImpl mFragments = new FragmentManagerImpl();
-    final FragmentContainer mContainer = new FragmentContainer() {
-        @Override
-        @Nullable
-        public View findViewById(int id) {
-            return Activity.this.findViewById(id);
-        }
-        @Override
-        public boolean hasView() {
-            Window window = Activity.this.getWindow();
-            return (window != null && window.peekDecorView() != null);
-        }
-    };
+    // we must have a handler before the FragmentController is constructed
+    final Handler mHandler = new Handler();
+    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
 
     // Most recent call to requestVisibleBehind().
     boolean mVisibleBehind;
 
-    ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
-    LoaderManagerImpl mLoaderManager;
-
     private static final class ManagedCursor {
         ManagedCursor(Cursor cursor) {
             mCursor = cursor;
@@ -802,7 +788,6 @@
     private final Object mInstanceTracker = StrictMode.trackActivity(this);
 
     private Thread mUiThread;
-    final Handler mHandler = new Handler();
 
     ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
     SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK;
@@ -863,28 +848,7 @@
      * Return the LoaderManager for this activity, creating it if needed.
      */
     public LoaderManager getLoaderManager() {
-        if (mLoaderManager != null) {
-            return mLoaderManager;
-        }
-        mCheckedForLoaderManager = true;
-        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
-        return mLoaderManager;
-    }
-
-    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
-        if (mAllLoaderManagers == null) {
-            mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
-        }
-        LoaderManagerImpl lm = mAllLoaderManagers.get(who);
-        if (lm == null) {
-            if (create) {
-                lm = new LoaderManagerImpl(who, this, started);
-                mAllLoaderManagers.put(who, lm);
-            }
-        } else {
-            lm.updateActivity(this);
-        }
-        return lm;
+        return mFragments.getLoaderManager();
     }
 
     /**
@@ -931,7 +895,7 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
         if (mLastNonConfigurationInstances != null) {
-            mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
+            mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
         }
         if (mActivityInfo.parentActivityName != null) {
             if (mActionBar == null) {
@@ -1172,15 +1136,7 @@
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
         mCalled = true;
 
-        if (!mLoadersStarted) {
-            mLoadersStarted = true;
-            if (mLoaderManager != null) {
-                mLoaderManager.doStart();
-            } else if (!mCheckedForLoaderManager) {
-                mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
-            }
-            mCheckedForLoaderManager = true;
-        }
+        mFragments.doLoaderStart();
 
         getApplication().dispatchActivityStarted(this);
     }
@@ -1873,27 +1829,9 @@
     NonConfigurationInstances retainNonConfigurationInstances() {
         Object activity = onRetainNonConfigurationInstance();
         HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
-        ArrayList<Fragment> fragments = mFragments.retainNonConfig();
-        boolean retainLoaders = false;
-        if (mAllLoaderManagers != null) {
-            // prune out any loader managers that were already stopped and so
-            // have nothing useful to retain.
-            final int N = mAllLoaderManagers.size();
-            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
-            for (int i=N-1; i>=0; i--) {
-                loaders[i] = mAllLoaderManagers.valueAt(i);
-            }
-            for (int i=0; i<N; i++) {
-                LoaderManagerImpl lm = loaders[i];
-                if (lm.mRetaining) {
-                    retainLoaders = true;
-                } else {
-                    lm.doDestroy();
-                    mAllLoaderManagers.remove(lm.mWho);
-                }
-            }
-        }
-        if (activity == null && children == null && fragments == null && !retainLoaders
+        List<Fragment> fragments = mFragments.retainNonConfig();
+        ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
+        if (activity == null && children == null && fragments == null && loaders == null
                 && mVoiceInteractor == null) {
             return null;
         }
@@ -1902,7 +1840,7 @@
         nci.activity = activity;
         nci.children = children;
         nci.fragments = fragments;
-        nci.loaders = mAllLoaderManagers;
+        nci.loaders = loaders;
         nci.voiceInteractor = mVoiceInteractor;
         return nci;
     }
@@ -1924,18 +1862,7 @@
      * with this activity.
      */
     public FragmentManager getFragmentManager() {
-        return mFragments;
-    }
-
-    void invalidateFragment(String who) {
-        //Log.v(TAG, "invalidateFragmentIndex: index=" + index);
-        if (mAllLoaderManagers != null) {
-            LoaderManagerImpl lm = mAllLoaderManagers.get(who);
-            if (lm != null && !lm.mRetaining) {
-                lm.doDestroy();
-                mAllLoaderManagers.remove(who);
-            }
-        }
+        return mFragments.getFragmentManager();
     }
 
     /**
@@ -2518,7 +2445,7 @@
             return;
         }
 
-        if (!mFragments.popBackStackImmediate()) {
+        if (!mFragments.getFragmentManager().popBackStackImmediate()) {
             finishAfterTransition();
         }
     }
@@ -5518,21 +5445,13 @@
                 writer.print(mResumed); writer.print(" mStopped=");
                 writer.print(mStopped); writer.print(" mFinished=");
                 writer.println(mFinished);
-        writer.print(innerPrefix); writer.print("mLoadersStarted=");
-                writer.println(mLoadersStarted);
         writer.print(innerPrefix); writer.print("mChangingConfigurations=");
                 writer.println(mChangingConfigurations);
         writer.print(innerPrefix); writer.print("mCurrentConfig=");
                 writer.println(mCurrentConfig);
 
-        if (mLoaderManager != null) {
-            writer.print(prefix); writer.print("Loader Manager ");
-                    writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
-                    writer.println(":");
-            mLoaderManager.dump(prefix + "  ", fd, writer, args);
-        }
-
-        mFragments.dump(prefix, fd, writer, args);
+        mFragments.dumpLoaders(innerPrefix, fd, writer, args);
+        mFragments.getFragmentManager().dump(innerPrefix, fd, writer, args);
 
         if (getWindow() != null &&
                 getWindow().peekDecorView() != null &&
@@ -6128,7 +6047,7 @@
             Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
         attachBaseContext(context);
 
-        mFragments.attachActivity(this, mContainer, null);
+        mFragments.attachHost(null /*parent*/);
 
         mWindow = new PhoneWindow(this);
         mWindow.setCallback(this);
@@ -6211,18 +6130,7 @@
                 " did not call through to super.onStart()");
         }
         mFragments.dispatchStart();
-        if (mAllLoaderManagers != null) {
-            final int N = mAllLoaderManagers.size();
-            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
-            for (int i=N-1; i>=0; i--) {
-                loaders[i] = mAllLoaderManagers.valueAt(i);
-            }
-            for (int i=0; i<N; i++) {
-                LoaderManagerImpl lm = loaders[i];
-                lm.finishRetain();
-                lm.doReportStart();
-            }
-        }
+        mFragments.reportLoaderStart();
         mActivityTransitionState.enterReady(this);
     }
 
@@ -6328,16 +6236,7 @@
 
     final void performStop() {
         mDoReportFullyDrawn = false;
-        if (mLoadersStarted) {
-            mLoadersStarted = false;
-            if (mLoaderManager != null) {
-                if (!mChangingConfigurations) {
-                    mLoaderManager.doStop();
-                } else {
-                    mLoaderManager.doRetain();
-                }
-            }
-        }
+        mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
 
         if (!mStopped) {
             if (mWindow != null) {
@@ -6379,9 +6278,7 @@
         mWindow.destroy();
         mFragments.dispatchDestroy();
         onDestroy();
-        if (mLoaderManager != null) {
-            mLoaderManager.doDestroy();
-        }
+        mFragments.doLoaderDestroy();
         if (mVoiceInteractor != null) {
             mVoiceInteractor.detachActivity();
         }
@@ -6541,4 +6438,74 @@
         return intent != null
                 && PackageManager.ACTION_REQUEST_PERMISSIONS.equals(intent.getAction());
     }
+
+    class HostCallbacks extends FragmentHostCallback<Activity> {
+        public HostCallbacks() {
+            super(Activity.this /*activity*/);
+        }
+
+        @Override
+        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            Activity.this.dump(prefix, fd, writer, args);
+        }
+
+        @Override
+        public boolean onShouldSaveFragmentState(Fragment fragment) {
+            return !isFinishing();
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            final LayoutInflater result = Activity.this.getLayoutInflater();
+            if (onUseFragmentManagerInflaterFactory()) {
+                return result.cloneInContext(Activity.this);
+            }
+            return result;
+        }
+
+        @Override
+        public boolean onUseFragmentManagerInflaterFactory() {
+            // Newer platform versions use the child fragment manager's LayoutInflaterFactory.
+            return getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
+        }
+
+        @Override
+        public Activity onGetHost() {
+            return Activity.this;
+        }
+
+        @Override
+        public void onInvalidateOptionsMenu() {
+            Activity.this.invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,
+                Bundle options) {
+            Activity.this.startActivityFromFragment(fragment, intent, requestCode, options);
+        }
+
+        @Override
+        public boolean onHasWindowAnimations() {
+            return getWindow() != null;
+        }
+
+        @Override
+        public int onGetWindowAnimations() {
+            final Window w = getWindow();
+            return (w == null) ? 0 : w.getAttributes().windowAnimations;
+        }
+
+        @Nullable
+        @Override
+        public View onFindViewById(int id) {
+            return Activity.this.findViewById(id);
+        }
+
+        @Override
+        public boolean onHasView() {
+            final Window w = getWindow();
+            return (w != null && w.peekDecorView() != null);
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9bad9bb..2e45b79 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -114,7 +114,6 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
-import java.security.Security;
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.List;
@@ -5338,7 +5337,7 @@
         // Set the reporter for event logging in libcore
         EventLogger.setReporter(new EventLoggingReporter());
 
-        Security.addProvider(new AndroidKeyStoreProvider());
+        AndroidKeyStoreProvider.install();
 
         // Make sure TrustedCertificateStore looks in the right place for CA certificates
         final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 9d1d312..b0fda9c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -26,6 +26,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.text.TextUtils;
+import libcore.util.ZoneInfoDB;
+
+import java.io.IOException;
 
 /**
  * This class provides access to the system alarm services.  These allow you
@@ -151,6 +155,7 @@
 
     private final IAlarmManager mService;
     private final boolean mAlwaysExact;
+    private final int mTargetSdkVersion;
 
 
     /**
@@ -159,8 +164,8 @@
     AlarmManager(IAlarmManager service, Context ctx) {
         mService = service;
 
-        final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
-        mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
+        mTargetSdkVersion = ctx.getApplicationInfo().targetSdkVersion;
+        mAlwaysExact = (mTargetSdkVersion < Build.VERSION_CODES.KITKAT);
     }
 
     private long legacyExactLength() {
@@ -585,12 +590,38 @@
     }
 
     /**
-     * Set the system default time zone.
-     * Requires the permission android.permission.SET_TIME_ZONE.
+     * Sets the system's persistent default time zone. This is the time zone for all apps, even
+     * after a reboot. Use {@link java.util.TimeZone#setDefault} if you just want to change the
+     * time zone within your app, and even then prefer to pass an explicit
+     * {@link java.util.TimeZone} to APIs that require it rather than changing the time zone for
+     * all threads.
      *
-     * @param timeZone in the format understood by {@link java.util.TimeZone}
+     * <p> On android M and above, it is an error to pass in a non-Olson timezone to this
+     * function. Note that this is a bad idea on all Android releases because POSIX and
+     * the {@code TimeZone} class have opposite interpretations of {@code '+'} and {@code '-'}
+     * in the same non-Olson ID.
+     *
+     * @param timeZone one of the Olson ids from the list returned by
+     *     {@link java.util.TimeZone#getAvailableIDs}
      */
     public void setTimeZone(String timeZone) {
+        if (TextUtils.isEmpty(timeZone)) {
+            return;
+        }
+
+        // Reject this timezone if it isn't an Olson zone we recognize.
+        if (mTargetSdkVersion >= Build.VERSION_CODES.MNC) {
+            boolean hasTimeZone = false;
+            try {
+                hasTimeZone = ZoneInfoDB.getInstance().hasTimeZone(timeZone);
+            } catch (IOException ignored) {
+            }
+
+            if (!hasTimeZone) {
+                throw new IllegalArgumentException("Timezone: " + timeZone + " is not an Olson ID");
+            }
+        }
+
         try {
             mService.setTimeZone(timeZone);
         } catch (RemoteException ex) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 223d528..8a3c9c8 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -217,12 +217,17 @@
     public static final int OP_READ_PHONE_STATE = 51;
     /** @hide Add voicemail messages to the voicemail content provider. */
     public static final int OP_ADD_VOICEMAIL = 52;
+    /** @hide Access APIs for SIP calling over VOIP or WiFi. */
+    public static final int OP_USE_SIP = 53;
+    /** @hide Intercept outgoing calls. */
+    public static final int OP_PROCESS_OUTGOING_CALLS = 54;
+    /** @hide User the fingerprint API. */
+    public static final int OP_USE_FINGERPRINT = 55;
     /** @hide */
-    public static final int _NUM_OP = 53;
+    public static final int _NUM_OP = 56;
 
     /** Access to coarse location information. */
-    public static final String OPSTR_COARSE_LOCATION =
-            "android:coarse_location";
+    public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
     /** Access to fine location information. */
     public static final String OPSTR_FINE_LOCATION =
             "android:fine_location";
@@ -237,7 +242,59 @@
             = "android:get_usage_stats";
     /** Activate a VPN connection without user intervention. @hide */
     @SystemApi
-    public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
+    public static final String OPSTR_ACTIVATE_VPN
+            = "android:activate_vpn";
+    /** @hide Allows an application to read the user's contacts data. */
+    public static final String OPSTR_READ_CONTACTS
+            = "android:read_contacts";
+    /** @hide Allows an application to write to the user's contacts data. */
+    public static final String OPSTR_WRITE_CONTACTS
+            = "android:write_contacts";
+    /** @hide Allows an application to read the user's call log. */
+    public static final String OPSTR_READ_CALL_LOG
+            = "android:read_call_log";
+    /** @hide Allows an application to write to the user's call log. */
+    public static final String OPSTR_WRITE_CALL_LOG
+            = "android:write_call_log";
+    /** @hide Allows an application to read the user's calendar data. */
+    public static final String OPSTR_READ_CALENDAR
+            = "android:read_calendar";
+    /** @hide Allows an application to write to the user's calendar data. */
+    public static final String OPSTR_WRITE_CALENDAR
+            = "android:write_calendar";
+    /** @hide Allows an application to initiate a phone call. */
+    public static final String OPSTR_CALL_PHONE
+            = "android:call_phone";
+    /** @hide Allows an application to read SMS messages. */
+    public static final String OPSTR_READ_SMS
+            = "android:read_sms";
+    /** @hide Allows an application to receive SMS messages. */
+    public static final String OPSTR_RECEIVE_SMS
+            = "android:receive_sms";
+    /** @hide Allows an application to receive MMS messages. */
+    public static final String OPSTR_RECEIVE_MMS
+            = "android:receive_mms";
+    /** @hide Allows an application to receive WAP push messages. */
+    public static final String OPSTR_RECEIVE_WAP_PUSH
+            = "android:receive_wap_push";
+    /** @hide Allows an application to send SMS messages. */
+    public static final String OPSTR_SEND_SMS
+            = "android:send_sms";
+    /** @hide Allows an application to add system alert windows. */
+    public static final String OPSTR_SYSTEM_ALERT_WINDOW
+            = "android:system_alert_window";
+    /** @hide Required to be able to access the camera device. */
+    public static final String OPSTR_CAMERA
+            = "android:camera";
+    /** @hide Required to be able to access the microphone device. */
+    public static final String OPSTR_RECORD_AUDIO
+            = "android:record_audio";
+    /** @hide Required to access phone state related information. */
+    public static final String OPSTR_READ_PHONE_STATE
+            = "android:read_phone_state";
+    /** @hide Required to access phone state related information. */
+    public static final String OPSTR_ADD_VOICEMAIL
+            = "android:add_voicemail";
 
     /**
      * This maps each operation to the operation that serves as the
@@ -300,7 +357,10 @@
             OP_ASSIST_STRUCTURE,
             OP_ASSIST_SCREENSHOT,
             OP_READ_PHONE_STATE,
-            OP_ADD_VOICEMAIL
+            OP_ADD_VOICEMAIL,
+            OP_USE_SIP,
+            OP_PROCESS_OUTGOING_CALLS,
+            OP_USE_FINGERPRINT
     };
 
     /**
@@ -360,6 +420,9 @@
             null,
             null,
             null,
+            null,
+            null,
+            null,
             null
     };
 
@@ -420,7 +483,10 @@
             "ASSIST_STRUCTURE",
             "ASSIST_SCREENSHOT",
             "OP_READ_PHONE_STATE",
-            "ADD_VOICEMAIL"
+            "ADD_VOICEMAIL",
+            "USE_SIP",
+            "PROCESS_OUTGOING_CALLS",
+            "USE_FINGERPRINT"
     };
 
     /**
@@ -480,7 +546,10 @@
             null, // no permission for receiving assist structure
             null, // no permission for receiving assist screenshot
             Manifest.permission.READ_PHONE_STATE,
-            Manifest.permission.ADD_VOICEMAIL
+            Manifest.permission.ADD_VOICEMAIL,
+            Manifest.permission.USE_SIP,
+            Manifest.permission.PROCESS_OUTGOING_CALLS,
+            Manifest.permission.USE_FINGERPRINT
     };
 
     /**
@@ -541,7 +610,10 @@
             null, // ASSIST_STRUCTURE
             null, // ASSIST_SCREENSHOT
             null, // READ_PHONE_STATE
-            null // ADD_VOICEMAIL
+            null, // ADD_VOICEMAIL
+            null, // USE_SIP
+            null, // PROCESS_OUTGOING_CALLS
+            null  // USE_FINGERPRINT
     };
 
     /**
@@ -601,7 +673,10 @@
             false, //ASSIST_STRUCTURE
             false, //ASSIST_SCREENSHOT
             false, //READ_PHONE_STATE
-            false  //ADD_VOICEMAIL
+            false, //ADD_VOICEMAIL
+            false, // USE_SIP
+            false, // PROCESS_OUTGOING_CALLS
+            false  // USE_FINGERPRINT
     };
 
     /**
@@ -660,6 +735,9 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED
     };
 
@@ -723,9 +801,39 @@
             false,
             false,
             false,
+            false,
+            false,
+            false,
             false
     };
 
+    /**
+     * This is a mapping from a permission name to public app op name.
+     */
+    private static final ArrayMap<String, String> sPermToOp = new ArrayMap<>();
+    static {
+        sPermToOp.put(Manifest.permission.ACCESS_COARSE_LOCATION, OPSTR_COARSE_LOCATION);
+        sPermToOp.put(Manifest.permission.ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION);
+        sPermToOp.put(Manifest.permission.PACKAGE_USAGE_STATS, OPSTR_GET_USAGE_STATS);
+        sPermToOp.put(Manifest.permission.READ_CONTACTS, OPSTR_READ_CONTACTS);
+        sPermToOp.put(Manifest.permission.WRITE_CONTACTS, OPSTR_WRITE_CONTACTS);
+        sPermToOp.put(Manifest.permission.READ_CALL_LOG, OPSTR_READ_CALL_LOG);
+        sPermToOp.put(Manifest.permission.WRITE_CALL_LOG, OPSTR_WRITE_CALL_LOG);
+        sPermToOp.put(Manifest.permission.READ_CALENDAR, OPSTR_READ_CALENDAR);
+        sPermToOp.put(Manifest.permission.WRITE_CALENDAR, OPSTR_WRITE_CALENDAR);
+        sPermToOp.put(Manifest.permission.CALL_PHONE, OPSTR_CALL_PHONE);
+        sPermToOp.put(Manifest.permission.READ_SMS, OPSTR_READ_SMS);
+        sPermToOp.put(Manifest.permission.RECEIVE_SMS, OPSTR_RECEIVE_SMS);
+        sPermToOp.put(Manifest.permission.RECEIVE_MMS, OPSTR_RECEIVE_MMS);
+        sPermToOp.put(Manifest.permission.RECEIVE_WAP_PUSH, OPSTR_RECEIVE_WAP_PUSH);
+        sPermToOp.put(Manifest.permission.SEND_SMS, OPSTR_SEND_SMS);
+        sPermToOp.put(Manifest.permission.SYSTEM_ALERT_WINDOW, OPSTR_SYSTEM_ALERT_WINDOW);
+        sPermToOp.put(Manifest.permission.CAMERA, OPSTR_CAMERA);
+        sPermToOp.put(Manifest.permission.RECORD_AUDIO, OPSTR_RECORD_AUDIO);
+        sPermToOp.put(Manifest.permission.READ_PHONE_STATE, OPSTR_READ_PHONE_STATE);
+        sPermToOp.put(Manifest.permission.ADD_VOICEMAIL, OPSTR_ADD_VOICEMAIL);
+    }
+
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
 
     static {
@@ -1066,6 +1174,21 @@
     }
 
     /**
+     * Gets the app op name associated with a given permission.
+     * The app op name is one of the public constants defined
+     * in this class such as {@link #OPSTR_COARSE_LOCATION}.
+     *
+     * @param permission The permission.
+     * @return The app op associated with the permission or null.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static String permissionToOp(String permission) {
+        return sPermToOp.get(permission);
+    }
+
+    /**
      * Monitor for changes to the operating mode for the given op in the given app package.
      * @param op The operation to monitor, one of OPSTR_*.
      * @param packageName The name of the application to monitor.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 16a2430..90293a4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -62,6 +62,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -79,6 +80,7 @@
 import dalvik.system.VMRuntime;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
 
@@ -1560,13 +1562,7 @@
     public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() {
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
         final String volumeUuid = storage.getPrimaryStorageUuid();
-        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
-            return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
-        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
-            return storage.getPrimaryPhysicalVolume();
-        } else {
-            return storage.findVolumeByUuid(volumeUuid);
-        }
+        return storage.findVolumeByQualifiedUuid(volumeUuid);
     }
 
     @Override
@@ -2054,7 +2050,7 @@
     /** {@hide} */
     private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements
             Handler.Callback {
-        private static final int MSG_STARTED = 1;
+        private static final int MSG_CREATED = 1;
         private static final int MSG_STATUS_CHANGED = 2;
 
         final MoveCallback mCallback;
@@ -2067,26 +2063,38 @@
 
         @Override
         public boolean handleMessage(Message msg) {
-            final int moveId = msg.arg1;
             switch (msg.what) {
-                case MSG_STARTED:
-                    mCallback.onStarted(moveId, (String) msg.obj);
+                case MSG_CREATED: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    mCallback.onCreated(args.argi1, (Bundle) args.arg2);
+                    args.recycle();
                     return true;
-                case MSG_STATUS_CHANGED:
-                    mCallback.onStatusChanged(moveId, msg.arg2, (long) msg.obj);
+                }
+                case MSG_STATUS_CHANGED: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    mCallback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
+                    args.recycle();
                     return true;
+                }
             }
             return false;
         }
 
         @Override
-        public void onStarted(int moveId, String title) {
-            mHandler.obtainMessage(MSG_STARTED, moveId, 0, title).sendToTarget();
+        public void onCreated(int moveId, Bundle extras) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = moveId;
+            args.arg2 = extras;
+            mHandler.obtainMessage(MSG_CREATED, args).sendToTarget();
         }
 
         @Override
         public void onStatusChanged(int moveId, int status, long estMillis) {
-            mHandler.obtainMessage(MSG_STATUS_CHANGED, moveId, status, estMillis).sendToTarget();
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = moveId;
+            args.argi2 = status;
+            args.arg3 = estMillis;
+            mHandler.obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
         }
     }
 
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index 9946d79..3abbb5b 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -224,6 +224,7 @@
         static final int FLAGS_CHECKED = 0x00000200;
         static final int FLAGS_CLICKABLE = 0x00004000;
         static final int FLAGS_LONG_CLICKABLE = 0x00200000;
+        static final int FLAGS_STYLUS_BUTTON_PRESSABLE = 0x00400000;
 
         int mFlags;
 
@@ -401,6 +402,10 @@
             return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
         }
 
+        public boolean isStylusButtonPressable() {
+            return (mFlags&ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE) != 0;
+        }
+
         public String getClassName() {
             return mClassName;
         }
@@ -513,6 +518,12 @@
         }
 
         @Override
+        public void setStylusButtonPressable(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE)
+                    | (state ? ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE : 0);
+        }
+
+        @Override
         public void setFocusable(boolean state) {
             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
                     | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 8fb048b..49644a7 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -416,14 +416,14 @@
 
     public CharSequence getBreadCrumbTitle() {
         if (mBreadCrumbTitleRes != 0) {
-            return mManager.mActivity.getText(mBreadCrumbTitleRes);
+            return mManager.mHost.getContext().getText(mBreadCrumbTitleRes);
         }
         return mBreadCrumbTitleText;
     }
 
     public CharSequence getBreadCrumbShortTitle() {
         if (mBreadCrumbShortTitleRes != 0) {
-            return mManager.mActivity.getText(mBreadCrumbShortTitleRes);
+            return mManager.mHost.getContext().getText(mBreadCrumbShortTitleRes);
         }
         return mBreadCrumbShortTitleText;
     }
@@ -868,7 +868,7 @@
      */
     private void calculateFragments(SparseArray<Fragment> firstOutFragments,
             SparseArray<Fragment> lastInFragments) {
-        if (!mManager.mContainer.hasView()) {
+        if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
         Op op = mHead;
@@ -926,7 +926,7 @@
      */
     public void calculateBackFragments(SparseArray<Fragment> firstOutFragments,
             SparseArray<Fragment> lastInFragments) {
-        if (!mManager.mContainer.hasView()) {
+        if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
         Op op = mHead;
@@ -1002,7 +1002,7 @@
         // Adding a non-existent target view makes sure that the transitions don't target
         // any views by default. They'll only target the views we tell add. If we don't
         // add any, then no views will be targeted.
-        state.nonExistentView = new View(mManager.mActivity);
+        state.nonExistentView = new View(mManager.mHost.getContext());
 
         // Go over all leaving fragments.
         for (int i = 0; i < firstOutFragments.size(); i++) {
@@ -1275,7 +1275,7 @@
      */
     private void configureTransitions(int containerId, TransitionState state, boolean isBack,
             SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
-        ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
+        ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.onFindViewById(containerId);
         if (sceneRoot != null) {
             Fragment inFragment = lastInFragments.get(containerId);
             Fragment outFragment = firstOutFragments.get(containerId);
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index bde5a61..2fb8cc2 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -410,7 +410,7 @@
             return (LayoutInflater)mDialog.getContext().getSystemService(
                     Context.LAYOUT_INFLATER_SERVICE);
         }
-        return (LayoutInflater)mActivity.getSystemService(
+        return (LayoutInflater) mHost.getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
     }
     
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 4fdae7f..91d810e 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -26,7 +26,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -94,19 +93,20 @@
         mSavedFragmentState = in.readBundle();
     }
 
-    public Fragment instantiate(Activity activity, Fragment parent) {
+    public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
         if (mInstance != null) {
             return mInstance;
         }
 
+        final Context context = host.getContext();
         if (mArguments != null) {
-            mArguments.setClassLoader(activity.getClassLoader());
+            mArguments.setClassLoader(context.getClassLoader());
         }
 
-        mInstance = Fragment.instantiate(activity, mClassName, mArguments);
+        mInstance = Fragment.instantiate(context, mClassName, mArguments);
 
         if (mSavedFragmentState != null) {
-            mSavedFragmentState.setClassLoader(activity.getClassLoader());
+            mSavedFragmentState.setClassLoader(context.getClassLoader());
             mInstance.mSavedFragmentState = mSavedFragmentState;
         }
         mInstance.setIndex(mIndex, parent);
@@ -117,7 +117,7 @@
         mInstance.mTag = mTag;
         mInstance.mRetainInstance = mRetainInstance;
         mInstance.mDetached = mDetached;
-        mInstance.mFragmentManager = activity.mFragments;
+        mInstance.mFragmentManager = host.mFragmentManager;
         if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
                 "Instantiated fragment " + mInstance);
 
@@ -425,7 +425,7 @@
     FragmentManagerImpl mFragmentManager;
 
     // Activity this fragment is attached to.
-    Activity mActivity;
+    FragmentHostCallback mHost;
 
     // Private fragment manager for child fragments inside of this one.
     FragmentManagerImpl mChildFragmentManager;
@@ -775,20 +775,36 @@
     }
 
     /**
+     * Return the {@link Context} this fragment is currently associated with.
+     */
+    public Context getContext() {
+        return mHost == null ? null : mHost.getContext();
+    }
+
+    /**
      * Return the Activity this fragment is currently associated with.
      */
     final public Activity getActivity() {
-        return mActivity;
+        return mHost == null ? null : mHost.getActivity();
+    }
+
+    /**
+     * Return the host object of this fragment. May return {@code null} if the fragment
+     * isn't currently being hosted.
+     */
+    @Nullable
+    final public Object getHost() {
+        return mHost == null ? null : mHost.onGetHost();
     }
 
     /**
      * Return <code>getActivity().getResources()</code>.
      */
     final public Resources getResources() {
-        if (mActivity == null) {
+        if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
-        return mActivity.getResources();
+        return mHost.getContext().getResources();
     }
 
     /**
@@ -870,7 +886,7 @@
      * Return true if the fragment is currently added to its activity.
      */
     final public boolean isAdded() {
-        return mActivity != null && mAdded;
+        return mHost != null && mAdded;
     }
 
     /**
@@ -1037,11 +1053,11 @@
         if (mLoaderManager != null) {
             return mLoaderManager;
         }
-        if (mActivity == null) {
+        if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
+        mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
         return mLoaderManager;
     }
 
@@ -1065,15 +1081,15 @@
      * Context.startActivity(Intent, Bundle)} for more details.
      */
     public void startActivity(Intent intent, Bundle options) {
-        if (mActivity == null) {
+        if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
         if (options != null) {
-            mActivity.startActivityFromFragment(this, intent, -1, options);
+            mHost.onStartActivityFromFragment(this, intent, -1, options);
         } else {
             // Note we want to go through this call for compatibility with
             // applications that may have overridden the method.
-            mActivity.startActivityFromFragment(this, intent, -1);
+            mHost.onStartActivityFromFragment(this, intent, -1, null /*options*/);
         }
     }
 
@@ -1090,10 +1106,10 @@
      * containing Activity.
      */
     public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
-        if (mActivity == null) {
+        if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
-        mActivity.startActivityFromFragment(this, intent, requestCode, options);
+        mHost.onStartActivityFromFragment(this, intent, requestCode, options);
     }
 
     /**
@@ -1181,11 +1197,12 @@
      * @see android.content.Context#checkSelfPermission(String)
      */
     public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
-        if (mActivity == null) {
+        if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
-        Intent intent = mActivity.getPackageManager().buildRequestPermissionsIntent(permissions);
-        mActivity.startActivityFromFragment(this, intent, requestCode, null);
+        Intent intent =
+                mHost.getContext().getPackageManager().buildRequestPermissionsIntent(permissions);
+        mHost.onStartActivityFromFragment(this, intent, requestCode, null);
     }
 
     /**
@@ -1211,19 +1228,16 @@
      * inflation.  Maybe this should become a public API. Note sure.
      */
     public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
-        // Newer platform versions use the child fragment manager's LayoutInflaterFactory.
-        if (mActivity.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
-            LayoutInflater result = mActivity.getLayoutInflater().cloneInContext(mActivity);
+        final LayoutInflater result = mHost.onGetLayoutInflater();
+        if (mHost.onUseFragmentManagerInflaterFactory()) {
             getChildFragmentManager(); // Init if needed; use raw implementation below.
             result.setPrivateFactory(mChildFragmentManager.getLayoutInflaterFactory());
-            return result;
-        } else {
-            return mActivity.getLayoutInflater();
         }
+        return result;
     }
 
     /**
-     * @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead.
+     * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
      */
     @Deprecated
     public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
@@ -1266,29 +1280,29 @@
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java
      *      create}
      *
-     * @param activity The Activity that is inflating this fragment.
+     * @param context The Context that is inflating this fragment.
      * @param attrs The attributes at the tag where the fragment is
      * being created.
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
+    public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
         onInflate(attrs, savedInstanceState);
         mCalled = true;
 
-        TypedArray a = activity.obtainStyledAttributes(attrs,
+        TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.Fragment);
-        mEnterTransition = loadTransition(activity, a, mEnterTransition, null,
+        mEnterTransition = loadTransition(context, a, mEnterTransition, null,
                 com.android.internal.R.styleable.Fragment_fragmentEnterTransition);
-        mReturnTransition = loadTransition(activity, a, mReturnTransition, USE_DEFAULT_TRANSITION,
+        mReturnTransition = loadTransition(context, a, mReturnTransition, USE_DEFAULT_TRANSITION,
                 com.android.internal.R.styleable.Fragment_fragmentReturnTransition);
-        mExitTransition = loadTransition(activity, a, mExitTransition, null,
+        mExitTransition = loadTransition(context, a, mExitTransition, null,
                 com.android.internal.R.styleable.Fragment_fragmentExitTransition);
-        mReenterTransition = loadTransition(activity, a, mReenterTransition, USE_DEFAULT_TRANSITION,
+        mReenterTransition = loadTransition(context, a, mReenterTransition, USE_DEFAULT_TRANSITION,
                 com.android.internal.R.styleable.Fragment_fragmentReenterTransition);
-        mSharedElementEnterTransition = loadTransition(activity, a, mSharedElementEnterTransition,
+        mSharedElementEnterTransition = loadTransition(context, a, mSharedElementEnterTransition,
                 null, com.android.internal.R.styleable.Fragment_fragmentSharedElementEnterTransition);
-        mSharedElementReturnTransition = loadTransition(activity, a, mSharedElementReturnTransition,
+        mSharedElementReturnTransition = loadTransition(context, a, mSharedElementReturnTransition,
                 USE_DEFAULT_TRANSITION,
                 com.android.internal.R.styleable.Fragment_fragmentSharedElementReturnTransition);
         if (mAllowEnterTransitionOverlap == null) {
@@ -1303,9 +1317,30 @@
     }
 
     /**
-     * Called when a fragment is first attached to its activity.
+     * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
+     */
+    @Deprecated
+    public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
+        mCalled = true;
+    }
+
+    /**
+     * Called when a fragment is first attached to its context.
      * {@link #onCreate(Bundle)} will be called after this.
      */
+    public void onAttach(Context context) {
+        mCalled = true;
+        final Activity hostActivity = mHost == null ? null : mHost.getActivity();
+        if (hostActivity != null) {
+            mCalled = false;
+            onAttach(hostActivity);
+        }
+    }
+
+    /**
+     * @deprecated Use {@link #onAttach(Context)} instead.
+     */
+    @Deprecated
     public void onAttach(Activity activity) {
         mCalled = true;
     }
@@ -1428,7 +1463,7 @@
             mLoadersStarted = true;
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
-                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+                mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
             }
             if (mLoaderManager != null) {
                 mLoaderManager.doStart();
@@ -1521,7 +1556,7 @@
         //        + " mLoaderManager=" + mLoaderManager);
         if (!mCheckedForLoaderManager) {
             mCheckedForLoaderManager = true;
-            mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+            mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
         }
         if (mLoaderManager != null) {
             mLoaderManager.doDestroy();
@@ -1546,7 +1581,7 @@
         mBackStackNesting = 0;
         mFragmentManager = null;
         mChildFragmentManager = null;
-        mActivity = null;
+        mHost = null;
         mFragmentId = 0;
         mContainerId = 0;
         mTag = null;
@@ -2034,9 +2069,9 @@
             writer.print(prefix); writer.print("mFragmentManager=");
             writer.println(mFragmentManager);
         }
-        if (mActivity != null) {
-            writer.print(prefix); writer.print("mActivity=");
-            writer.println(mActivity);
+        if (mHost != null) {
+            writer.print(prefix); writer.print("mHost=");
+            writer.println(mHost);
         }
         if (mParentFragment != null) {
             writer.print(prefix); writer.print("mParentFragment=");
@@ -2094,10 +2129,10 @@
 
     void instantiateChildFragmentManager() {
         mChildFragmentManager = new FragmentManagerImpl();
-        mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
+        mChildFragmentManager.attachController(mHost, new FragmentContainer() {
             @Override
             @Nullable
-            public View findViewById(int id) {
+            public View onFindViewById(int id) {
                 if (mView == null) {
                     throw new IllegalStateException("Fragment does not have a view");
                 }
@@ -2105,7 +2140,7 @@
             }
 
             @Override
-            public boolean hasView() {
+            public boolean onHasView() {
                 return (mView != null);
             }
         }, this);
@@ -2319,13 +2354,13 @@
             mLoadersStarted = false;
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
-                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+                mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
             }
             if (mLoaderManager != null) {
-                if (mActivity == null || !mActivity.mChangingConfigurations) {
-                    mLoaderManager.doStop();
-                } else {
+                if (mRetaining) {
                     mLoaderManager.doRetain();
+                } else {
+                    mLoaderManager.doStop();
                 }
             }
         }
diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java
new file mode 100644
index 0000000..b2e0300
--- /dev/null
+++ b/core/java/android/app/FragmentContainer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.IdRes;
+import android.annotation.Nullable;
+import android.view.View;
+
+/**
+ * Callbacks to a {@link Fragment}'s container.
+ */
+public abstract class FragmentContainer {
+    /**
+     * Return the view with the given resource ID. May return {@code null} if the
+     * view is not a child of this container.
+     */
+    @Nullable
+    public abstract View onFindViewById(@IdRes int id);
+
+    /**
+     * Return {@code true} if the container holds any view.
+     */
+    public abstract boolean onHasView();
+}
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
new file mode 100644
index 0000000..28dadfa
--- /dev/null
+++ b/core/java/android/app/FragmentController.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Provides integration points with a {@link FragmentManager} for a fragment host.
+ * <p>
+ * It is the responsibility of the host to take care of the Fragment's lifecycle.
+ * The methods provided by {@link FragmentController} are for that purpose.
+ */
+public class FragmentController {
+    private final FragmentHostCallback<?> mHost;
+
+    /**
+     * Returns a {@link FragmentController}.
+     */
+    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
+        return new FragmentController(callbacks);
+    }
+
+    private FragmentController(FragmentHostCallback<?> callbacks) {
+        mHost = callbacks;
+    }
+
+    /**
+     * Returns a {@link FragmentManager} for this controller.
+     */
+    public FragmentManager getFragmentManager() {
+        return mHost.getFragmentManagerImpl();
+    }
+
+    /**
+     * Returns a {@link LoaderManager}.
+     */
+    public LoaderManager getLoaderManager() {
+        return mHost.getLoaderManagerImpl();
+    }
+
+    /**
+     * Returns a fragment with the given identifier.
+     */
+    @Nullable
+    public Fragment findFragmentByWho(String who) {
+        return mHost.mFragmentManager.findFragmentByWho(who);
+    }
+
+    /**
+     * Attaches the host to the FragmentManager for this controller. The host must be
+     * attached before the FragmentManager can be used to manage Fragments.
+     * */
+    public void attachHost(Fragment parent) {
+        mHost.mFragmentManager.attachController(
+                mHost, mHost /*container*/, parent);
+    }
+
+    /**
+     * Instantiates a Fragment's view.
+     *
+     * @param parent The parent that the created view will be placed
+     * in; <em>note that this may be null</em>.
+     * @param name Tag name to be inflated.
+     * @param context The context the view is being created in.
+     * @param attrs Inflation attributes as specified in XML file.
+     *
+     * @return view the newly created view
+     */
+    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        return mHost.mFragmentManager.onCreateView(parent, name, context, attrs);
+    }
+
+    /**
+     * Marks the fragment state as unsaved. This allows for "state loss" detection.
+     */
+    public void noteStateNotSaved() {
+        mHost.mFragmentManager.noteStateNotSaved();
+    }
+
+    /**
+     * Saves the state for all Fragments.
+     */
+    public Parcelable saveAllState() {
+        return mHost.mFragmentManager.saveAllState();
+    }
+
+    /**
+     * Restores the saved state for all Fragments. The given Fragment list are Fragment
+     * instances retained across configuration changes.
+     *
+     * @see #retainNonConfig()
+     */
+    public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
+        mHost.mFragmentManager.restoreAllState(state, nonConfigList);
+    }
+
+    /**
+     * Returns a list of Fragments that have opted to retain their instance across
+     * configuration changes.
+     */
+    public List<Fragment> retainNonConfig() {
+        return mHost.mFragmentManager.retainNonConfig();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the create state.
+     * <p>Call when Fragments should be created.
+     *
+     * @see Fragment#onCreate(Bundle)
+     */
+    public void dispatchCreate() {
+        mHost.mFragmentManager.dispatchCreate();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the activity created state.
+     * <p>Call when Fragments should be informed their host has been created.
+     *
+     * @see Fragment#onActivityCreated(Bundle)
+     */
+    public void dispatchActivityCreated() {
+        mHost.mFragmentManager.dispatchActivityCreated();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the start state.
+     * <p>Call when Fragments should be started.
+     *
+     * @see Fragment#onStart()
+     */
+    public void dispatchStart() {
+        mHost.mFragmentManager.dispatchStart();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the resume state.
+     * <p>Call when Fragments should be resumed.
+     *
+     * @see Fragment#onResume()
+     */
+    public void dispatchResume() {
+        mHost.mFragmentManager.dispatchResume();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the pause state.
+     * <p>Call when Fragments should be paused.
+     *
+     * @see Fragment#onPause()
+     */
+    public void dispatchPause() {
+        mHost.mFragmentManager.dispatchPause();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the stop state.
+     * <p>Call when Fragments should be stopped.
+     *
+     * @see Fragment#onStop()
+     */
+    public void dispatchStop() {
+        mHost.mFragmentManager.dispatchStop();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the destroy view state.
+     * <p>Call when the Fragment's views should be destroyed.
+     *
+     * @see Fragment#onDestroyView()
+     */
+    public void dispatchDestroyView() {
+        mHost.mFragmentManager.dispatchDestroyView();
+    }
+
+    /**
+     * Moves all Fragments managed by the controller's FragmentManager
+     * into the destroy state.
+     * <p>Call when Fragments should be destroyed.
+     *
+     * @see Fragment#onDestroy()
+     */
+    public void dispatchDestroy() {
+        mHost.mFragmentManager.dispatchDestroy();
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know a configuration change occurred.
+     * <p>Call when there is a configuration change.
+     *
+     * @see Fragment#onConfigurationChanged(Configuration)
+     */
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know the device is in a low memory condition.
+     * <p>Call when the device is low on memory and Fragment's should trim
+     * their memory usage.
+     *
+     * @see Fragment#onLowMemory()
+     */
+    public void dispatchLowMemory() {
+        mHost.mFragmentManager.dispatchLowMemory();
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know they should trim their memory usage.
+     * <p>Call when the Fragment can release allocated memory [such as if
+     * the Fragment is in the background].
+     *
+     * @see Fragment#onTrimMemory(int)
+     */
+    public void dispatchTrimMemory(int level) {
+        mHost.mFragmentManager.dispatchTrimMemory(level);
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know they should create an options menu.
+     * <p>Call when the Fragment should create an options menu.
+     *
+     * @return {@code true} if the options menu contains items to display
+     * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater)
+     */
+    public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know they should prepare their options menu for display.
+     * <p>Call immediately before displaying the Fragment's options menu.
+     *
+     * @return {@code true} if the options menu contains items to display
+     * @see Fragment#onPrepareOptionsMenu(Menu)
+     */
+    public boolean dispatchPrepareOptionsMenu(Menu menu) {
+        return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu);
+    }
+
+    /**
+     * Sends an option item selection event to the Fragments managed by the
+     * controller's FragmentManager. Once the event has been consumed,
+     * no additional handling will be performed.
+     * <p>Call immediately after an options menu item has been selected
+     *
+     * @return {@code true} if the options menu selection event was consumed
+     * @see Fragment#onOptionsItemSelected(MenuItem)
+     */
+    public boolean dispatchOptionsItemSelected(MenuItem item) {
+        return mHost.mFragmentManager.dispatchOptionsItemSelected(item);
+    }
+
+    /**
+     * Sends a context item selection event to the Fragments managed by the
+     * controller's FragmentManager. Once the event has been consumed,
+     * no additional handling will be performed.
+     * <p>Call immediately after an options menu item has been selected
+     *
+     * @return {@code true} if the context menu selection event was consumed
+     * @see Fragment#onContextItemSelected(MenuItem)
+     */
+    public boolean dispatchContextItemSelected(MenuItem item) {
+        return mHost.mFragmentManager.dispatchContextItemSelected(item);
+    }
+
+    /**
+     * Lets all Fragments managed by the controller's FragmentManager
+     * know their options menu has closed.
+     * <p>Call immediately after closing the Fragment's options menu.
+     *
+     * @see Fragment#onOptionsMenuClosed(Menu)
+     */
+    public void dispatchOptionsMenuClosed(Menu menu) {
+        mHost.mFragmentManager.dispatchOptionsMenuClosed(menu);
+    }
+
+    /**
+     * Execute any pending actions for the Fragments managed by the
+     * controller's FragmentManager.
+     * <p>Call when queued actions can be performed [eg when the
+     * Fragment moves into a start or resume state].
+     * @return {@code true} if queued actions were performed
+     */
+    public boolean execPendingActions() {
+        return mHost.mFragmentManager.execPendingActions();
+    }
+
+    /**
+     * Starts the loaders.
+     */
+    public void doLoaderStart() {
+        mHost.doLoaderStart();
+    }
+
+    /**
+     * Stops the loaders, optionally retaining their state. This is useful for keeping the
+     * loader state across configuration changes.
+     *
+     * @param retain When {@code true}, the loaders aren't stopped, but, their instances
+     * are retained in a started state
+     */
+    public void doLoaderStop(boolean retain) {
+        mHost.doLoaderStop(retain);
+    }
+
+    /**
+     * Destroys the loaders and, if their state is not being retained, removes them.
+     */
+    public void doLoaderDestroy() {
+        mHost.doLoaderDestroy();
+    }
+
+    /**
+     * Lets the loaders know the host is ready to receive notifications.
+     */
+    public void reportLoaderStart() {
+        mHost.reportLoaderStart();
+    }
+
+    /**
+     * Returns a list of LoaderManagers that have opted to retain their instance across
+     * configuration changes.
+     */
+    public ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+        return mHost.retainLoaderNonConfig();
+    }
+
+    /**
+     * Restores the saved state for all LoaderManagers. The given LoaderManager list are
+     * LoaderManager instances retained across configuration changes.
+     *
+     * @see #retainLoaderNonConfig()
+     */
+    public void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
+        mHost.restoreLoaderNonConfig(loaderManagers);
+    }
+
+    /**
+     * Dumps the current state of the loaders.
+     */
+    public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        mHost.dumpLoaders(prefix, fd, writer, args);
+    }
+}
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
new file mode 100644
index 0000000..dad2c79
--- /dev/null
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Integration points with the Fragment host.
+ * <p>
+ * Fragments may be hosted by any object; such as an {@link Activity}. In order to
+ * host fragments, implement {@link FragmentHostCallback}, overriding the methods
+ * applicable to the host.
+ */
+public abstract class FragmentHostCallback<E> extends FragmentContainer {
+    private final Activity mActivity;
+    final Context mContext;
+    private final Handler mHandler;
+    final int mWindowAnimations;
+    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
+    private ArrayMap<String, LoaderManager> mAllLoaderManagers;
+    private LoaderManagerImpl mLoaderManager;
+    private boolean mCheckedForLoaderManager;
+    private boolean mLoadersStarted;
+
+    public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
+        this(null /*activity*/, context, handler, windowAnimations);
+    }
+
+    FragmentHostCallback(Activity activity) {
+        this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
+    }
+
+    FragmentHostCallback(Activity activity, Context context, Handler handler,
+            int windowAnimations) {
+        mActivity = activity;
+        mContext = context;
+        mHandler = handler;
+        mWindowAnimations = windowAnimations;
+    }
+
+    /**
+     * Print internal state into the given stream.
+     *
+     * @param prefix Desired prefix to prepend at each line of output.
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param writer The PrintWriter to which you should dump your state. This will be closed
+     *                  for you after you return.
+     * @param args additional arguments to the dump request.
+     */
+    public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+    }
+
+    /**
+     * Return {@code true} if the fragment's state needs to be saved.
+     */
+    public boolean onShouldSaveFragmentState(Fragment fragment) {
+        return true;
+    }
+
+    /**
+     * Return a {@link LayoutInflater}.
+     * See {@link Activity#getLayoutInflater()}.
+     */
+    public LayoutInflater onGetLayoutInflater() {
+        return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+
+    /**
+     * Return {@code true} if the FragmentManager's LayoutInflaterFactory should be used.
+     */
+    public boolean onUseFragmentManagerInflaterFactory() {
+        return false;
+    }
+
+    /**
+     * Return the object that's currently hosting the fragment. If a {@link Fragment}
+     * is hosted by a {@link Activity}, the object returned here should be the same
+     * object returned from {@link Fragment#getActivity()}.
+     */
+    @Nullable
+    public abstract E onGetHost();
+
+    /**
+     * Invalidates the activity's options menu.
+     * See {@link Activity#invalidateOptionsMenu()}
+     */
+    public void onInvalidateOptionsMenu() {
+    }
+
+    /**
+     * Starts a new {@link Activity} from the given fragment.
+     * See {@link Activity#startActivityForResult(Intent, int)}.
+     */
+    public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,
+            Bundle options) {
+        if (requestCode != -1) {
+            throw new IllegalStateException(
+                    "Starting activity with a requestCode requires a FragmentActivity host");
+        }
+        mContext.startActivity(intent);
+    }
+
+    /**
+     * Return {@code true} if there are window animations.
+     */
+    public boolean onHasWindowAnimations() {
+        return true;
+    }
+
+    /**
+     * Return the window animations.
+     */
+    public int onGetWindowAnimations() {
+        return mWindowAnimations;
+    }
+
+    @Nullable
+    @Override
+    public View onFindViewById(int id) {
+        return null;
+    }
+
+    @Override
+    public boolean onHasView() {
+        return true;
+    }
+
+    Activity getActivity() {
+        return mActivity;
+    }
+
+    Context getContext() {
+        return mContext;
+    }
+
+    Handler getHandler() {
+        return mHandler;
+    }
+
+    FragmentManagerImpl getFragmentManagerImpl() {
+        return mFragmentManager;
+    }
+
+    LoaderManagerImpl getLoaderManagerImpl() {
+        if (mLoaderManager != null) {
+            return mLoaderManager;
+        }
+        mCheckedForLoaderManager = true;
+        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
+        return mLoaderManager;
+    }
+
+    void inactivateFragment(String who) {
+        //Log.v(TAG, "invalidateSupportFragment: who=" + who);
+        if (mAllLoaderManagers != null) {
+            LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+            if (lm != null && !lm.mRetaining) {
+                lm.doDestroy();
+                mAllLoaderManagers.remove(who);
+            }
+        }
+    }
+
+    void onFragmentInflate(Fragment fragment, AttributeSet attrs, Bundle savedInstanceState) {
+        fragment.onInflate(mContext, attrs, savedInstanceState);
+    }
+
+    void onFragmentAttach(Fragment fragment) {
+        fragment.onAttach(mContext);
+    }
+
+    void doLoaderStart() {
+        if (mLoadersStarted) {
+            return;
+        }
+        mLoadersStarted = true;
+
+        if (mLoaderManager != null) {
+            mLoaderManager.doStart();
+        } else if (!mCheckedForLoaderManager) {
+            mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
+        }
+        mCheckedForLoaderManager = true;
+    }
+
+    void doLoaderStop(boolean retain) {
+        if (mLoaderManager == null) {
+            return;
+        }
+
+        if (!mLoadersStarted) {
+            return;
+        }
+        mLoadersStarted = false;
+
+        if (retain) {
+            mLoaderManager.doRetain();
+        } else {
+            mLoaderManager.doStop();
+        }
+    }
+
+    void doLoaderRetain() {
+        if (mLoaderManager == null) {
+            return;
+        }
+        mLoaderManager.doRetain();
+    }
+
+    void doLoaderDestroy() {
+        if (mLoaderManager == null) {
+            return;
+        }
+        mLoaderManager.doDestroy();
+    }
+
+    void reportLoaderStart() {
+        if (mAllLoaderManagers != null) {
+            final int N = mAllLoaderManagers.size();
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+            for (int i=N-1; i>=0; i--) {
+                loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+            }
+            for (int i=0; i<N; i++) {
+                LoaderManagerImpl lm = loaders[i];
+                lm.finishRetain();
+                lm.doReportStart();
+            }
+        }
+    }
+
+    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
+        if (mAllLoaderManagers == null) {
+            mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
+        }
+        LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+        if (lm == null) {
+            if (create) {
+                lm = new LoaderManagerImpl(who, this, started);
+                mAllLoaderManagers.put(who, lm);
+            }
+        } else {
+            lm.updateHostController(this);
+        }
+        return lm;
+    }
+
+    ArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+        boolean retainLoaders = false;
+        if (mAllLoaderManagers != null) {
+            // prune out any loader managers that were already stopped and so
+            // have nothing useful to retain.
+            final int N = mAllLoaderManagers.size();
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+            for (int i=N-1; i>=0; i--) {
+                loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+            }
+            for (int i=0; i<N; i++) {
+                LoaderManagerImpl lm = loaders[i];
+                if (lm.mRetaining) {
+                    retainLoaders = true;
+                } else {
+                    lm.doDestroy();
+                    mAllLoaderManagers.remove(lm.mWho);
+                }
+            }
+        }
+
+        if (retainLoaders) {
+            return mAllLoaderManagers;
+        }
+        return null;
+    }
+
+    void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
+        mAllLoaderManagers = loaderManagers;
+    }
+
+    void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        writer.print(prefix); writer.print("mLoadersStarted=");
+        writer.println(mLoadersStarted);
+        if (mLoaderManager != null) {
+            writer.print(prefix); writer.print("Loader Manager ");
+            writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
+            writer.println(":");
+            mLoaderManager.dump(prefix + "  ", fd, writer, args);
+        }
+    }
+}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 975b20d..62436e9 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -19,9 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
-import android.annotation.Nullable;
 import android.content.Context;
-import android.annotation.IdRes;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.os.Bundle;
@@ -48,6 +46,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Interface for interacting with {@link Fragment} objects inside of an
@@ -393,15 +392,6 @@
 }
 
 /**
- * Callbacks from FragmentManagerImpl to its container.
- */
-interface FragmentContainer {
-    @Nullable
-    public View findViewById(@IdRes int id);
-    public boolean hasView();
-}
-
-/**
  * Container for fragments associated with an activity.
  */
 final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
@@ -430,7 +420,8 @@
     ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
 
     int mCurState = Fragment.INITIALIZING;
-    Activity mActivity;
+    FragmentHostCallback<?> mHost;
+    FragmentController mController;
     FragmentContainer mContainer;
     Fragment mParent;
     
@@ -455,10 +446,10 @@
         Log.e(TAG, ex.getMessage());
         LogWriter logw = new LogWriter(Log.ERROR, TAG);
         PrintWriter pw = new FastPrintWriter(logw, false, 1024);
-        if (mActivity != null) {
+        if (mHost != null) {
             Log.e(TAG, "Activity state:");
             try {
-                mActivity.dump("  ", null, pw, new String[] { });
+                mHost.onDump("  ", null, pw, new String[] { });
             } catch (Exception e) {
                 pw.flush();
                 Log.e(TAG, "Failed dumping state", e);
@@ -490,7 +481,7 @@
     public void popBackStack() {
         enqueueAction(new Runnable() {
             @Override public void run() {
-                popBackStackState(mActivity.mHandler, null, -1, 0);
+                popBackStackState(mHost.getHandler(), null, -1, 0);
             }
         }, false);
     }
@@ -499,14 +490,14 @@
     public boolean popBackStackImmediate() {
         checkStateLoss();
         executePendingTransactions();
-        return popBackStackState(mActivity.mHandler, null, -1, 0);
+        return popBackStackState(mHost.getHandler(), null, -1, 0);
     }
 
     @Override
     public void popBackStack(final String name, final int flags) {
         enqueueAction(new Runnable() {
             @Override public void run() {
-                popBackStackState(mActivity.mHandler, name, -1, flags);
+                popBackStackState(mHost.getHandler(), name, -1, flags);
             }
         }, false);
     }
@@ -515,7 +506,7 @@
     public boolean popBackStackImmediate(String name, int flags) {
         checkStateLoss();
         executePendingTransactions();
-        return popBackStackState(mActivity.mHandler, name, -1, flags);
+        return popBackStackState(mHost.getHandler(), name, -1, flags);
     }
 
     @Override
@@ -525,7 +516,7 @@
         }
         enqueueAction(new Runnable() {
             @Override public void run() {
-                popBackStackState(mActivity.mHandler, null, id, flags);
+                popBackStackState(mHost.getHandler(), null, id, flags);
             }
         }, false);
     }
@@ -537,7 +528,7 @@
         if (id < 0) {
             throw new IllegalArgumentException("Bad id: " + id);
         }
-        return popBackStackState(mActivity.mHandler, null, id, flags);
+        return popBackStackState(mHost.getHandler(), null, id, flags);
     }
 
     @Override
@@ -619,7 +610,7 @@
         if (mParent != null) {
             DebugUtils.buildShortClassTag(mParent, sb);
         } else {
-            DebugUtils.buildShortClassTag(mActivity, sb);
+            DebugUtils.buildShortClassTag(mHost, sb);
         }
         sb.append("}}");
         return sb.toString();
@@ -716,7 +707,7 @@
         }
 
         writer.print(prefix); writer.println("FragmentManager misc state:");
-        writer.print(prefix); writer.print("  mActivity="); writer.println(mActivity);
+        writer.print(prefix); writer.print("  mHost="); writer.println(mHost);
         writer.print(prefix); writer.print("  mContainer="); writer.println(mContainer);
         if (mParent != null) {
             writer.print(prefix); writer.print("  mParent="); writer.println(mParent);
@@ -747,7 +738,7 @@
         }
         
         if (fragment.mNextAnim != 0) {
-            Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
+            Animator anim = AnimatorInflater.loadAnimator(mHost.getContext(), fragment.mNextAnim);
             if (anim != null) {
                 return anim;
             }
@@ -762,14 +753,14 @@
             return null;
         }
         
-        if (transitionStyle == 0 && mActivity.getWindow() != null) {
-            transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
+        if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
+            transitionStyle = mHost.onGetWindowAnimations();
         }
         if (transitionStyle == 0) {
             return null;
         }
         
-        TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
+        TypedArray attrs = mHost.getContext().obtainStyledAttributes(transitionStyle,
                 com.android.internal.R.styleable.FragmentAnimation);
         int anim = attrs.getResourceId(styleIndex, 0);
         attrs.recycle();
@@ -778,7 +769,7 @@
             return null;
         }
         
-        return AnimatorInflater.loadAnimator(mActivity, anim);
+        return AnimatorInflater.loadAnimator(mHost.getContext(), anim);
     }
     
     public void performPendingDeferredStart(Fragment f) {
@@ -848,18 +839,18 @@
                             }
                         }
                     }
-                    f.mActivity = mActivity;
+                    f.mHost = mHost;
                     f.mParentFragment = mParent;
                     f.mFragmentManager = mParent != null
-                            ? mParent.mChildFragmentManager : mActivity.mFragments;
+                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                     f.mCalled = false;
-                    f.onAttach(mActivity);
+                    mHost.onFragmentAttach(f);
                     if (!f.mCalled) {
                         throw new SuperNotCalledException("Fragment " + f
                                 + " did not call through to super.onAttach()");
                     }
                     if (f.mParentFragment == null) {
-                        mActivity.onAttachFragment(f);
+                        mHost.onFragmentAttach(f);
                     }
 
                     if (!f.mRetaining) {
@@ -884,7 +875,7 @@
                         if (!f.mFromLayout) {
                             ViewGroup container = null;
                             if (f.mContainerId != 0) {
-                                container = (ViewGroup)mContainer.findViewById(f.mContainerId);
+                                container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
                                 if (container == null && !f.mRestored) {
                                     throwException(new IllegalArgumentException(
                                             "No view found for id 0x"
@@ -954,7 +945,7 @@
                         if (f.mView != null) {
                             // Need to save the current view state if not
                             // done already.
-                            if (!mActivity.isFinishing() && f.mSavedViewState == null) {
+                            if (!mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                 saveFragmentViewState(f);
                             }
                         }
@@ -1030,7 +1021,7 @@
                                 if (!f.mRetaining) {
                                     makeInactive(f);
                                 } else {
-                                    f.mActivity = null;
+                                    f.mHost = null;
                                     f.mParentFragment = null;
                                     f.mFragmentManager = null;
                                     f.mChildFragmentManager = null;
@@ -1053,7 +1044,7 @@
     }
     
     void moveToState(int newState, int transit, int transitStyle, boolean always) {
-        if (mActivity == null && newState != Fragment.INITIALIZING) {
+        if (mHost == null && newState != Fragment.INITIALIZING) {
             throw new IllegalStateException("No activity");
         }
 
@@ -1078,8 +1069,8 @@
                 startPendingDeferredFragments();
             }
 
-            if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
-                mActivity.invalidateOptionsMenu();
+            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
+                mHost.onInvalidateOptionsMenu();
                 mNeedMenuInvalidate = false;
             }
         }
@@ -1126,7 +1117,7 @@
             mAvailIndices = new ArrayList<Integer>();
         }
         mAvailIndices.add(f.mIndex);
-        mActivity.invalidateFragment(f.mWho);
+        mHost.inactivateFragment(f.mWho);
         f.initState();
     }
     
@@ -1349,7 +1340,7 @@
             checkStateLoss();
         }
         synchronized (this) {
-            if (mDestroyed || mActivity == null) {
+            if (mDestroyed || mHost == null) {
                 throw new IllegalStateException("Activity has been destroyed");
             }
             if (mPendingActions == null) {
@@ -1357,8 +1348,8 @@
             }
             mPendingActions.add(action);
             if (mPendingActions.size() == 1) {
-                mActivity.mHandler.removeCallbacks(mExecCommit);
-                mActivity.mHandler.post(mExecCommit);
+                mHost.getHandler().removeCallbacks(mExecCommit);
+                mHost.getHandler().post(mExecCommit);
             }
         }
     }
@@ -1427,7 +1418,7 @@
             throw new IllegalStateException("Recursive entry to executePendingTransactions");
         }
         
-        if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
+        if (Looper.myLooper() != mHost.getHandler().getLooper()) {
             throw new IllegalStateException("Must be called from main thread of process");
         }
 
@@ -1447,7 +1438,7 @@
                 }
                 mPendingActions.toArray(mTmpActions);
                 mPendingActions.clear();
-                mActivity.mHandler.removeCallbacks(mExecCommit);
+                mHost.getHandler().removeCallbacks(mExecCommit);
             }
             
             mExecutingActions = true;
@@ -1737,7 +1728,7 @@
         return fms;
     }
     
-    void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
+    void restoreAllState(Parcelable state, List<Fragment> nonConfig) {
         // If there is no saved state at all, then there can not be
         // any nonConfig fragments either, so that is that.
         if (state == null) return;
@@ -1758,7 +1749,7 @@
                 f.mAdded = false;
                 f.mTarget = null;
                 if (fs.mSavedFragmentState != null) {
-                    fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
+                    fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
                     f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
                             FragmentManagerImpl.VIEW_STATE_TAG);
                     f.mSavedFragmentState = fs.mSavedFragmentState;
@@ -1775,7 +1766,7 @@
         for (int i=0; i<fms.mActive.length; i++) {
             FragmentState fs = fms.mActive[i];
             if (fs != null) {
-                Fragment f = fs.instantiate(mActivity, mParent);
+                Fragment f = fs.instantiate(mHost, mParent);
                 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                 mActive.add(f);
                 // Now that the fragment is instantiated (or came from being
@@ -1851,9 +1842,10 @@
         }
     }
     
-    public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) {
-        if (mActivity != null) throw new IllegalStateException("Already attached");
-        mActivity = activity;
+    public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
+            Fragment parent) {
+        if (mHost != null) throw new IllegalStateException("Already attached");
+        mHost = host;
         mContainer = container;
         mParent = parent;
     }
@@ -1898,7 +1890,7 @@
         mDestroyed = true;
         execPendingActions();
         moveToState(Fragment.INITIALIZING, false);
-        mActivity = null;
+        mHost = null;
         mContainer = null;
         mParent = null;
     }
@@ -2024,8 +2016,8 @@
 
     @Override
     public void invalidateOptionsMenu() {
-        if (mActivity != null && mCurState == Fragment.RESUMED) {
-            mActivity.invalidateOptionsMenu();
+        if (mHost != null && mCurState == Fragment.RESUMED) {
+            mHost.onInvalidateOptionsMenu();
         } else {
             mNeedMenuInvalidate = true;
         }
@@ -2115,7 +2107,7 @@
             fragment.mTag = tag;
             fragment.mInLayout = true;
             fragment.mFragmentManager = this;
-            fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState);
+            mHost.onFragmentInflate(fragment, attrs, fragment.mSavedFragmentState);
             addFragment(fragment, true);
         } else if (fragment.mInLayout) {
             // A fragment already exists and it is not one we restored from
@@ -2132,7 +2124,7 @@
             // from last saved state), then give it the attributes to
             // initialize itself.
             if (!fragment.mRetaining) {
-                fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState);
+                mHost.onFragmentInflate(fragment, attrs, fragment.mSavedFragmentState);
             }
         }
 
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index ebb3c43..2c12317 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -199,9 +199,12 @@
     }
 
     /**
-     * Return whether the keyguard requires a password to unlock.
+     * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
+     * is currently locked.
      *
-     * @return true if keyguard is secure.
+     * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
+     *
+     * @return true if a PIN, pattern or password is set or a SIM card is locked.
      */
     public boolean isKeyguardSecure() {
         try {
@@ -240,12 +243,8 @@
     }
 
     /**
-     * Returns whether the device is currently locked and requires a PIN, pattern or
-     * password to unlock.
+     * Per-user version of {@link #isDeviceLocked()}.
      *
-     * @param userId the user for which the locked state should be reported.
-     * @return true if unlocking the device currently requires a PIN, pattern or
-     * password.
      * @hide
      */
     public boolean isDeviceLocked(int userId) {
@@ -260,6 +259,8 @@
      * Returns whether the device is secured with a PIN, pattern or
      * password.
      *
+     * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
+     *
      * @return true if a PIN, pattern or password was set.
      */
     public boolean isDeviceSecure() {
@@ -267,11 +268,8 @@
     }
 
     /**
-     * Returns whether the device is secured with a PIN, pattern or
-     * password.
+     * Per-user version of {@link #isDeviceSecure()}.
      *
-     * @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) {
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index b13b24a..f0e35c9 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -214,12 +214,12 @@
 
     final String mWho;
 
-    Activity mActivity;
     boolean mStarted;
     boolean mRetaining;
     boolean mRetainingStarted;
     
     boolean mCreatingLoader;
+    private FragmentHostCallback mHost;
 
     final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
             Loader.OnLoadCanceledListener<Object> {
@@ -356,15 +356,15 @@
             if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
                 if (DEBUG) Log.v(TAG, "  Reseting: " + this);
                 String lastBecause = null;
-                if (mActivity != null) {
-                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
-                    mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
+                if (mHost != null) {
+                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
+                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
                 }
                 try {
                     mCallbacks.onLoaderReset(mLoader);
                 } finally {
-                    if (mActivity != null) {
-                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
+                    if (mHost != null) {
+                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                     }
                 }
             }
@@ -465,25 +465,25 @@
                 mInactiveLoaders.remove(mId);
             }
 
-            if (mActivity != null && !hasRunningLoaders()) {
-                mActivity.mFragments.startPendingDeferredFragments();
+            if (mHost != null && !hasRunningLoaders()) {
+                mHost.mFragmentManager.startPendingDeferredFragments();
             }
         }
 
         void callOnLoadFinished(Loader<Object> loader, Object data) {
             if (mCallbacks != null) {
                 String lastBecause = null;
-                if (mActivity != null) {
-                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
-                    mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
+                if (mHost != null) {
+                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
+                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
                 }
                 try {
                     if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
                             + loader.dataToString(data));
                     mCallbacks.onLoadFinished(loader, data);
                 } finally {
-                    if (mActivity != null) {
-                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
+                    if (mHost != null) {
+                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                     }
                 }
                 mDeliveredData = true;
@@ -530,14 +530,14 @@
         }
     }
     
-    LoaderManagerImpl(String who, Activity activity, boolean started) {
+    LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
         mWho = who;
-        mActivity = activity;
+        mHost = host;
         mStarted = started;
     }
     
-    void updateActivity(Activity activity) {
-        mActivity = activity;
+    void updateHostController(FragmentHostCallback host) {
+        mHost = host;
     }
     
     private LoaderInfo createLoader(int id, Bundle args,
@@ -730,8 +730,8 @@
             mInactiveLoaders.removeAt(idx);
             info.destroy();
         }
-        if (mActivity != null && !hasRunningLoaders()) {
-            mActivity.mFragments.startPendingDeferredFragments();
+        if (mHost != null && !hasRunningLoaders()) {
+            mHost.mFragmentManager.startPendingDeferredFragments();
         }
     }
 
@@ -849,7 +849,7 @@
         sb.append("LoaderManager{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(" in ");
-        DebugUtils.buildShortClassTag(mActivity, sb);
+        DebugUtils.buildShortClassTag(mHost, sb);
         sb.append("}}");
         return sb.toString();
     }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 207519c..31d1ab7 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -63,12 +63,20 @@
             | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
             | DISABLE_SEARCH;
 
+    /**
+     * Flag to disable quick settings.
+     *
+     * Setting this flag disables quick settings completely, but does not disable expanding the
+     * notification shade.
+     */
+    public static final int DISABLE2_QUICK_SETTINGS = 0x00000001;
+
     public static final int DISABLE2_NONE = 0x00000000;
 
-    public static final int DISABLE2_MASK = 0x00000000;
+    public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS;
 
     @IntDef(flag = true,
-            value = {DISABLE2_NONE, DISABLE2_MASK})
+            value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Disable2Flags {}
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ed814c3..9f71ea5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -807,6 +807,24 @@
     public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED
             = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
 
+    /**
+     * Permission policy to prompt user for new permission requests for runtime permissions.
+     * Already granted or denied permissions are not affected by this.
+     */
+    public static final int PERMISSION_POLICY_PROMPT = 0;
+
+    /**
+     * Permission policy to always grant new permission requests for runtime permissions.
+     * Already granted or denied permissions are not affected by this.
+     */
+    public static final int PERMISSION_POLICY_AUTO_GRANT = 1;
+
+    /**
+     * Permission policy to always deny new permission requests for runtime permissions.
+     * Already granted or denied permissions are not affected by this.
+     */
+    public static final int PERMISSION_POLICY_AUTO_DENY = 2;
+
 
     /**
      * Return true if the given administrator component is currently
@@ -2908,7 +2926,7 @@
      *         the user has already been set up.
      */
     @SystemApi
-    public boolean setActiveProfileOwner(ComponentName admin, String ownerName)
+    public boolean setActiveProfileOwner(ComponentName admin, @Deprecated String ownerName)
             throws IllegalArgumentException {
         if (mService != null) {
             try {
@@ -2974,8 +2992,8 @@
      * @throws IllegalArgumentException if admin is null, the package isn't installed, or the
      * preconditions mentioned are not met.
      */
-    public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
-            throws IllegalArgumentException {
+    public boolean setProfileOwner(ComponentName admin, @Deprecated String ownerName,
+            int userHandle) throws IllegalArgumentException {
         if (admin == null) {
             throw new NullPointerException("admin cannot be null");
         }
@@ -4342,4 +4360,58 @@
             Log.w(TAG, "Failed talking with device policy service", re);
         }
     }
+
+    /**
+     * Called by profile or device owners to set the default response for future runtime permission
+     * requests by applications. The policy can allow for normal operation which prompts the
+     * user to grant a permission, or can allow automatic granting or denying of runtime
+     * permission requests by an application. This also applies to new permissions declared by app
+     * updates.
+     * @param admin Which profile or device owner this request is associated with.
+     * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT},
+     * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
+     */
+    public void setPermissionPolicy(ComponentName admin, int policy) {
+        try {
+            mService.setPermissionPolicy(admin, policy);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Failed talking with device policy service", re);
+        }
+    }
+
+    /**
+     * Returns the current runtime permission policy set by the device or profile owner. The
+     * default is {@link #PERMISSION_POLICY_PROMPT}.
+     * @param admin Which profile or device owner this request is associated with.
+     * @return the current policy for future permission requests.
+     */
+    public int getPermissionPolicy(ComponentName admin) {
+        try {
+            return mService.getPermissionPolicy(admin);
+        } catch (RemoteException re) {
+            return PERMISSION_POLICY_PROMPT;
+        }
+    }
+
+    /**
+     * Grants or revokes a runtime permission to a specific application so that the user
+     * does not have to be prompted. This might affect all permissions in a group that the
+     * runtime permission belongs to. This method can only be called by a profile or device
+     * owner.
+     * @param admin Which profile or device owner this request is associated with.
+     * @param packageName The application to grant or revoke a permission to.
+     * @param permission The permission to grant or revoke.
+     * @param granted Whether or not to grant the permission. If false, all permissions in the
+     * associated permission group will be denied.
+     * @return whether the permission was successfully granted or revoked
+     */
+    public boolean setPermissionGranted(ComponentName admin, String packageName,
+            String permission, boolean granted) {
+        try {
+            return mService.setPermissionGranted(admin, packageName, permission, granted);
+        } 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 a678c51..833bc00 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -229,4 +229,9 @@
     boolean getDoNotAskCredentialsOnBoot();
 
     void notifyPendingSystemUpdate(in long updateReceivedTime);
+
+    void setPermissionPolicy(in ComponentName admin, int policy);
+    int  getPermissionPolicy(in ComponentName admin);
+    boolean setPermissionGranted(in ComponentName admin, String packageName, String permission,
+            boolean granted);
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3044a94..9b4dcc6 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -34,6 +34,7 @@
 import android.os.ServiceManager;
 import android.app.ActivityThread;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.os.Binder;
 import android.util.Log;
 import android.util.Pair;
@@ -389,7 +390,7 @@
      * @hide
      */
     public static final String ACTION_BLE_STATE_CHANGED =
-        "anrdoid.bluetooth.adapter.action.BLE_STATE_CHANGED";
+        "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
 
     /**
      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
@@ -632,24 +633,6 @@
     }
 
     /**
-     * Returns true if LE only mode is enabled, that is apps
-     * have authorization to turn only BT ON and the calling
-     * app has privilage to do so
-     */
-    private boolean isLEAlwaysOnEnabled() {
-        boolean ret = false;
-        if (SystemProperties.getBoolean("ro.bluetooth.blealwayson", true) == true) {
-            Log.v(TAG, "LE always on mode is enabled");
-            // TODO: System API authorization check
-            ret = true;
-        } else {
-            Log.v(TAG, "LE always on mode is disabled");
-            ret = false;
-        }
-        return ret;
-    }
-
-    /**
      * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
      *
      * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
@@ -676,7 +659,7 @@
      * @hide
      */
     public boolean disableBLE() {
-        if (isLEAlwaysOnEnabled() != true) return false;
+        if (!isBleScanAlwaysAvailable()) return false;
 
         int state = getLeState();
         if (state == BluetoothAdapter.STATE_ON) {
@@ -738,7 +721,7 @@
      * @hide
      */
     public boolean enableBLE() {
-        if (isLEAlwaysOnEnabled() != true) return false;
+        if (!isBleScanAlwaysAvailable()) return false;
 
         if (isLeEnabled() == true) {
             if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
@@ -1243,8 +1226,12 @@
      */
     @SystemApi
     public boolean isBleScanAlwaysAvailable() {
-        // TODO: implement after Settings UI change.
-        return false;
+        try {
+            return mManagerService.isBleScanAlwaysAvailable();
+        } catch (RemoteException e) {
+            Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e);
+            return false;
+        }
     }
 
     /**
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 8d1ce99..0b81ee8 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -44,6 +44,8 @@
 
     String getAddress();
     String getName();
+
+    boolean isBleScanAlwaysAvailable();
     int updateBleAppCount(IBinder b, boolean enable);
     boolean isBleAppPresent();
 }
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index f103cae..dad486d 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -187,7 +187,7 @@
         mScanResultType = scanResultType;
         mReportDelayMillis = reportDelayMillis;
         mNumOfMatchesPerFilter = numOfMatchesPerFilter;
-        mMatchMode = numOfMatchesPerFilter;
+        mMatchMode = matchMode;
     }
 
     private ScanSettings(Parcel in) {
@@ -236,7 +236,7 @@
         private int mScanResultType = SCAN_RESULT_TYPE_FULL;
         private long mReportDelayMillis = 0;
         private int mMatchMode = MATCH_MODE_AGGRESSIVE;
-        private int mNumOfMatchesPerFilter  = MATCH_NUM_ONE_ADVERTISEMENT;
+        private int mNumOfMatchesPerFilter  = MATCH_NUM_MAX_ADVERTISEMENT;
         /**
          * Set scan mode for Bluetooth LE scan.
          *
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index f2e7fc4..4769bd0 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -593,7 +593,8 @@
 
             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
             int has = reply.readInt();
-            ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
+            ParcelFileDescriptor fd = has != 0 ? ParcelFileDescriptor.CREATOR
+                    .createFromParcel(reply) : null;
             return fd;
         } finally {
             data.recycle();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5eacce3..8687c6b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -252,6 +252,21 @@
     public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
 
     /**
+     * @hide Flag for {@link #bindService}: Like {@link #BIND_FOREGROUND_SERVICE},
+     * but only applies while the device is awake.
+     */
+    public static final int BIND_FOREGROUND_SERVICE_WHILE_AWAKE = 0x02000000;
+
+    /**
+     * @hide Flag for {@link #bindService}: For only the case where the binding
+     * is coming from the system, set the process state to FOREGROUND_SERVICE
+     * instead of the normal maximum of IMPORTANT_FOREGROUND.  That is, this is
+     * saying that the process shouldn't participate in the normal power reduction
+     * modes (removing network access etc).
+     */
+    public static final int BIND_FOREGROUND_SERVICE = 0x04000000;
+
+    /**
      * @hide Flag for {@link #bindService}: Treat the binding as hosting
      * an activity, an unbinding as the activity going in the background.
      * That is, when unbinding, the process when empty will go on the activity
@@ -374,24 +389,30 @@
     }
 
     /**
-     * Return a localized string from the application's package's
+     * Returns a localized string from the application's package's
      * default string table.
      *
      * @param resId Resource id for the string
+     * @return The string data associated with the resource, stripped of styled
+     *         text information.
      */
+    @NonNull
     public final String getString(@StringRes int resId) {
         return getResources().getString(resId);
     }
 
     /**
-     * Return a localized formatted string from the application's package's
+     * Returns a localized formatted string from the application's package's
      * default string table, substituting the format arguments as defined in
      * {@link java.util.Formatter} and {@link java.lang.String#format}.
      *
      * @param resId Resource id for the format string
-     * @param formatArgs The format arguments that will be used for substitution.
+     * @param formatArgs The format arguments that will be used for
+     *                   substitution.
+     * @return The string data associated with the resource, formatted and
+     *         stripped of styled text information.
      */
-
+    @NonNull
     public final String getString(@StringRes int resId, Object... formatArgs) {
         return getResources().getString(resId, formatArgs);
     }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ae59bfc..0b24594 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -58,6 +58,7 @@
  *  {@hide}
  */
 interface IPackageManager {
+    boolean isPackageFrozen(String packageName);
     boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
     int getPackageUid(String packageName, int userId);
diff --git a/core/java/android/content/pm/IPackageMoveObserver.aidl b/core/java/android/content/pm/IPackageMoveObserver.aidl
index 50ab3b5..86189fc 100644
--- a/core/java/android/content/pm/IPackageMoveObserver.aidl
+++ b/core/java/android/content/pm/IPackageMoveObserver.aidl
@@ -17,11 +17,13 @@
 
 package android.content.pm;
 
+import android.os.Bundle;
+
 /**
  * Callback for moving package resources from the Package Manager.
  * @hide
  */
 oneway interface IPackageMoveObserver {
-    void onStarted(int moveId, String title);
+    void onCreated(int moveId, in Bundle extras);
     void onStatusChanged(int moveId, int status, long estMillis);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e1c271d..7ff6ec3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -209,7 +209,14 @@
      * matching.  This is a synonym for including the CATEGORY_DEFAULT in your
      * supplied Intent.
      */
-    public static final int MATCH_DEFAULT_ONLY   = 0x00010000;
+    public static final int MATCH_DEFAULT_ONLY  = 0x00010000;
+
+    /**
+     * Querying flag: if set and if the platform is doing any filtering of the results, then
+     * the filtering will not happen. This is a synonym for saying that all results should
+     * be returned.
+     */
+    public static final int MATCH_ALL = 0x00020000;
 
     /**
      * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
@@ -2637,6 +2644,8 @@
      * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
      * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
      *
+     * You can also set {@link #MATCH_ALL} for preventing the filtering of the results.
+     *
      * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         Activity. These are ordered from best to worst match -- that
      *         is, the first item in the list is what is returned by
@@ -2658,6 +2667,8 @@
      * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
      * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
      *
+     * You can also set {@link #MATCH_ALL} for preventing the filtering of the results.
+     *
      * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         Activity. These are ordered from best to worst match -- that
      *         is, the first item in the list is what is returned by
@@ -4201,7 +4212,7 @@
 
     /** {@hide} */
     public static abstract class MoveCallback {
-        public abstract void onStarted(int moveId, String title);
+        public void onCreated(int moveId, Bundle extras) {}
         public abstract void onStatusChanged(int moveId, int status, long estMillis);
     }
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index fed9261..9596c42 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4315,9 +4315,6 @@
         // Additional data supplied by callers.
         public Object mExtras;
 
-        // Whether an operation is currently pending on this package
-        public boolean mOperationPending;
-
         // Applications hardware preferences
         public ArrayList<ConfigurationInfo> configPreferences = null;
 
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index fdafb04..14bfac5 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -271,7 +271,7 @@
             final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
                     R.styleable.ColorStateListItem);
             final int[] themeAttrs = a.extractThemeAttrs();
-            final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, 0);
+            final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, Color.MAGENTA);
             final float alphaMod = a.getFloat(R.styleable.ColorStateListItem_alpha, 1.0f);
 
             changingConfigurations |= a.getChangingConfigurations();
@@ -296,7 +296,9 @@
             }
             stateSpec = StateSet.trimStateSet(stateSpec, j);
 
-            // Apply alpha modulation.
+            // Apply alpha modulation. If we couldn't resolve the color or
+            // alpha yet, the default values leave us enough information to
+            // modulate again during applyTheme().
             final int color = modulateColorAlpha(baseColor, alphaMod);
             if (listSize == 0 || stateSpec.length == 0) {
                 defaultColor = color;
@@ -365,14 +367,31 @@
             if (themeAttrsList[i] != null) {
                 final TypedArray a = t.resolveAttributes(themeAttrsList[i],
                         R.styleable.ColorStateListItem);
+
+                final float defaultAlphaMod;
+                if (themeAttrsList[i][R.styleable.ColorStateListItem_color] != 0) {
+                    // If the base color hasn't been resolved yet, the current
+                    // color's alpha channel is either full-opacity (if we
+                    // haven't resolved the alpha modulation yet) or
+                    // pre-modulated. Either is okay as a default value.
+                    defaultAlphaMod = Color.alpha(mColors[i]) / 255.0f;
+                } else {
+                    // Otherwise, the only correct default value is 1. Even if
+                    // nothing is resolved during this call, we can apply this
+                    // multiple times without losing of information.
+                    defaultAlphaMod = 1.0f;
+                }
+
                 final int baseColor = a.getColor(
                         R.styleable.ColorStateListItem_color, mColors[i]);
                 final float alphaMod = a.getFloat(
-                        R.styleable.ColorStateListItem_alpha, 1.0f);
-
+                        R.styleable.ColorStateListItem_alpha, defaultAlphaMod);
                 mColors[i] = modulateColorAlpha(baseColor, alphaMod);
+
+                // Account for any configuration changes.
                 mChangingConfigurations |= a.getChangingConfigurations();
 
+                // Extract the theme attributes, if any.
                 themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
                 if (themeAttrsList[i] != null) {
                     hasUnresolvedAttrs = true;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 334d180..6e77e33 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -393,10 +393,11 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      *
      * @return String The string data associated with the resource,
-     * stripped of styled text information.
+     *         stripped of styled text information.
      */
+    @NonNull
     public String getString(@StringRes int id) throws NotFoundException {
-        CharSequence res = getText(id);
+        final CharSequence res = getText(id);
         if (res != null) {
             return res.toString();
         }
@@ -421,11 +422,11 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      *
      * @return String The string data associated with the resource,
-     * stripped of styled text information.
+     *         stripped of styled text information.
      */
-    public String getString(@StringRes int id, Object... formatArgs)
-            throws NotFoundException {
-        String raw = getString(id);
+    @NonNull
+    public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
+        final String raw = getString(id);
         return String.format(mConfiguration.locale, raw, formatArgs);
     }
 
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 0cf8df1..aeddf03 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -114,6 +114,11 @@
      * the Surface provided to prepare must not be used as a target of a CaptureRequest submitted
      * to this session.</p>
      *
+     * <p>{@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}
+     * devices cannot pre-allocate output buffers; for those devices,
+     * {@link StateCallback#onSurfacePrepared} will be immediately called, and no preallocation is
+     * done.</p>
+     *
      * @param surface the output Surface for which buffers should be pre-allocated. Must be one of
      * the output Surfaces used to create this session.
      *
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 87a1ca9..19e821c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -603,10 +603,9 @@
     /**
      * <p>List of available high speed video size and fps range configurations
      * supported by the camera device, in the format of (width, height, fps_min, fps_max).</p>
-     * <p>When HIGH_SPEED_VIDEO is supported in {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes},
-     * this metadata will list the supported high speed video size and fps range
-     * configurations. All the sizes listed in this configuration will be a subset
-     * of the sizes reported by StreamConfigurationMap#getOutputSizes for processed
+     * <p>When HIGH_SPEED_VIDEO is supported in {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}, this metadata
+     * will list the supported high speed video size and fps range configurations. All the sizes
+     * listed in this configuration will be a subset of the sizes reported by {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } for processed
      * non-stalling formats.</p>
      * <p>For the high speed video use case, where the application will set
      * {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} to HIGH_SPEED_VIDEO in capture requests, the application must
@@ -1116,11 +1115,12 @@
      * into the 3 stream types as below:</p>
      * <ul>
      * <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
-     * Typically JPEG format (ImageFormat#JPEG).</li>
-     * <li>Raw formats: ImageFormat#RAW_SENSOR, ImageFormat#RAW10, ImageFormat#RAW12,
-     * and ImageFormat#RAW_OPAQUE.</li>
+     *   Typically {@link android.graphics.ImageFormat#JPEG JPEG format}.</li>
+     * <li>Raw formats: {@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}, {@link android.graphics.ImageFormat#RAW10 RAW10}, or {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
      * <li>Processed (but not-stalling): any non-RAW format without a stall duration.
-     * Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li>
+     *   Typically {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
+     *   {@link android.graphics.ImageFormat#NV21 NV21}, or
+     *   {@link android.graphics.ImageFormat#YV12 YV12}.</li>
      * </ul>
      * <p><b>Range of valid values:</b><br></p>
      * <p>For processed (and stalling) format streams, &gt;= 1.</p>
@@ -1148,10 +1148,9 @@
      * be any <code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
      * <p>In particular, a <code>RAW</code> format is typically one of:</p>
      * <ul>
-     * <li>ImageFormat#RAW_SENSOR</li>
-     * <li>ImageFormat#RAW10</li>
-     * <li>ImageFormat#RAW12</li>
-     * <li>Opaque <code>RAW</code></li>
+     * <li>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</li>
+     * <li>{@link android.graphics.ImageFormat#RAW10 RAW10}</li>
+     * <li>{@link android.graphics.ImageFormat#RAW12 RAW12}</li>
      * </ul>
      * <p>LEGACY mode devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> LEGACY)
      * never support raw streams.</p>
@@ -1180,13 +1179,13 @@
      * <p>Processed (but not-stalling) is defined as any non-RAW format without a stall duration.
      * Typically:</p>
      * <ul>
-     * <li>ImageFormat#YUV_420_888</li>
-     * <li>ImageFormat#NV21</li>
-     * <li>ImageFormat#YV12</li>
-     * <li>Implementation-defined formats, i.e. StreamConfiguration#isOutputSupportedFor(Class)</li>
+     * <li>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</li>
+     * <li>{@link android.graphics.ImageFormat#NV21 NV21}</li>
+     * <li>{@link android.graphics.ImageFormat#YV12 YV12}</li>
+     * <li>Implementation-defined formats, i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#isOutputSupportedFor(Class) }</li>
      * </ul>
-     * <p>For full guarantees, query StreamConfigurationMap#getOutputStallDuration with
-     * a processed format -- it will return 0 for a non-stalling stream.</p>
+     * <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
+     * processed format -- it will return 0 for a non-stalling stream.</p>
      * <p>LEGACY devices will support at least 2 processing/non-stalling streams.</p>
      * <p><b>Range of valid values:</b><br></p>
      * <p>&gt;= 3
@@ -1212,10 +1211,11 @@
      * the camera device. Using more streams simultaneously may require more hardware and
      * CPU resources that will consume more power. The image format for this kind of an output stream can
      * be any non-<code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
-     * <p>A processed and stalling format is defined as any non-RAW format with a stallDurations &gt; 0.
-     * Typically only the <code>JPEG</code> format (ImageFormat#JPEG) is a stalling format.</p>
-     * <p>For full guarantees, query StreamConfigurationMap#getOutputStallDuration with
-     * a processed format -- it will return a non-0 value for a stalling stream.</p>
+     * <p>A processed and stalling format is defined as any non-RAW format with a stallDurations
+     * &gt; 0.  Typically only the {@link android.graphics.ImageFormat#JPEG JPEG format} is a
+     * stalling format.</p>
+     * <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
+     * processed format -- it will return a non-0 value for a stalling stream.</p>
      * <p>LEGACY devices will support up to 1 processing/stalling stream.</p>
      * <p><b>Range of valid values:</b><br></p>
      * <p>&gt;= 1</p>
@@ -1232,10 +1232,9 @@
      * <p>The maximum numbers of any type of input streams
      * that can be configured and used simultaneously by a camera device.</p>
      * <p>When set to 0, it means no input stream is supported.</p>
-     * <p>The image format for a input stream can be any supported
-     * format returned by StreamConfigurationMap#getInputFormats. When using an
-     * input stream, there must be at least one output stream
-     * configured to to receive the reprocessed images.</p>
+     * <p>The image format for a input stream can be any supported format returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats }. When using an
+     * input stream, there must be at least one output stream configured to to receive the
+     * reprocessed images.</p>
      * <p>When an input stream and some output streams are used in a reprocessing request,
      * only the input buffer will be used to produce these output stream buffers, and a
      * new sensor image will not be captured.</p>
@@ -1352,7 +1351,7 @@
 
     /**
      * <p>A list of all keys that the camera device has available
-     * to use with CaptureRequest.</p>
+     * to use with {@link android.hardware.camera2.CaptureRequest }.</p>
      * <p>Attempting to set a key into a CaptureRequest that is not
      * listed here will result in an invalid request and will be rejected
      * by the camera device.</p>
@@ -1370,7 +1369,7 @@
 
     /**
      * <p>A list of all keys that the camera device has available
-     * to use with CaptureResult.</p>
+     * to use with {@link android.hardware.camera2.CaptureResult }.</p>
      * <p>Attempting to get a key from a CaptureResult that is not
      * listed here will always return a <code>null</code> value. Getting a key from
      * a CaptureResult that is listed here will generally never return a <code>null</code>
@@ -1396,7 +1395,7 @@
 
     /**
      * <p>A list of all keys that the camera device has available
-     * to use with CameraCharacteristics.</p>
+     * to use with {@link android.hardware.camera2.CameraCharacteristics }.</p>
      * <p>This entry follows the same rules as
      * android.request.availableResultKeys (except that it applies for
      * CameraCharacteristics instead of CaptureResult). See above for more
@@ -1535,34 +1534,31 @@
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">PRIVATE (ImageFormat#PRIVATE)</td>
-     * <td align="left">JPEG</td>
+     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">PRIVATE</td>
-     * <td align="left">YUV_420_888</td>
+     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
      * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">YUV_420_888</td>
-     * <td align="left">JPEG</td>
+     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="left">YUV_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">YUV_420_888</td>
-     * <td align="left">YUV_420_888</td>
+     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
      * <td align="left">YUV_REPROCESSING</td>
      * </tr>
      * </tbody>
      * </table>
-     * <p>PRIVATE refers to a device-internal format that is not directly application-visible.
-     * A PRIVATE input surface can be acquired by
-     * ImageReader.newOpaqueInstance(width, height, maxImages).
-     * For a OPAQUE_REPROCESSING-capable camera device, using the PRIVATE format
-     * as either input or output will never hurt maximum frame rate (i.e.
-     * StreamConfigurationMap#getOutputStallDuration(format, size) is always 0),
-     * where format is ImageFormat#PRIVATE.</p>
+     * <p>PRIVATE refers to a device-internal format that is not directly application-visible.  A
+     * PRIVATE input surface can be acquired by {@link android.media.ImageReader#newOpaqueInstance }.</p>
+     * <p>For a OPAQUE_REPROCESSING-capable camera device, using the PRIVATE format as either input
+     * or output will never hurt maximum frame rate (i.e.  {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration getOutputStallDuration(ImageFormat.PRIVATE, size)} is always 0),</p>
      * <p>Attempting to configure an input stream with output streams not
      * listed as available in this map is not valid.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -1680,7 +1676,7 @@
      * android.scaler.availableStallDurations for more details about
      * calculating the max frame rate.</p>
      * <p>(Keep in sync with
-     * StreamConfigurationMap#getOutputMinFrameDuration)</p>
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p>This key is available on all devices.</p>
      *
@@ -1692,7 +1688,7 @@
 
     /**
      * <p>This lists the maximum stall duration for each
-     * format/size combination.</p>
+     * output format/size combination.</p>
      * <p>A stall duration is how much extra time would get added
      * to the normal minimum frame duration for a repeating request
      * that has streams with non-zero stall.</p>
@@ -1734,12 +1730,13 @@
      * ignored).</p>
      * <p>The following formats may always have a stall duration:</p>
      * <ul>
-     * <li>ImageFormat#JPEG</li>
-     * <li>ImageFormat#RAW_SENSOR</li>
+     * <li>{@link android.graphics.ImageFormat#JPEG }</li>
+     * <li>{@link android.graphics.ImageFormat#RAW_SENSOR }</li>
      * </ul>
      * <p>The following formats will never have a stall duration:</p>
      * <ul>
-     * <li>ImageFormat#YUV_420_888</li>
+     * <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li>
+     * <li>{@link android.graphics.ImageFormat#RAW10 }</li>
      * </ul>
      * <p>All other formats may or may not have an allowed stall duration on
      * a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
@@ -1747,7 +1744,7 @@
      * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
      * calculating the max frame rate (absent stalls).</p>
      * <p>(Keep up to date with
-     * StreamConfigurationMap#getOutputStallDuration(int, Size) )</p>
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } )</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p>This key is available on all devices.</p>
      *
@@ -1786,57 +1783,57 @@
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">JPEG</td>
+     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
      * <td align="center">Any</td>
      * <td align="center"></td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
+     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="center">1920x1080 (1080p)</td>
      * <td align="center">Any</td>
      * <td align="center">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
+     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="center">1280x720 (720)</td>
      * <td align="center">Any</td>
      * <td align="center">if 720p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
+     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="center">640x480 (480p)</td>
      * <td align="center">Any</td>
      * <td align="center">if 480p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
+     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
      * <td align="center">320x240 (240p)</td>
      * <td align="center">Any</td>
      * <td align="center">if 240p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
+     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
      * <td align="center">all output sizes available for JPEG</td>
      * <td align="center">FULL</td>
      * <td align="center"></td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
+     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
      * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
      * <td align="center">LIMITED</td>
      * <td align="center"></td>
      * </tr>
      * <tr>
-     * <td align="center">IMPLEMENTATION_DEFINED</td>
+     * <td align="center">{@link android.graphics.ImageFormat#PRIVATE }</td>
      * <td align="center">same as YUV_420_888</td>
      * <td align="center">Any</td>
      * <td align="center"></td>
      * </tr>
      * </tbody>
      * </table>
-     * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
-     * mandatory stream configurations on a per-capability basis.</p>
+     * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional mandatory
+     * stream configurations on a per-capability basis.</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
@@ -1973,8 +1970,8 @@
      * <p>Attempting to use frame durations beyond the maximum will result in the frame
      * duration being clipped to the maximum. See that control for a full definition of frame
      * durations.</p>
-     * <p>Refer to StreamConfigurationMap#getOutputMinFrameDuration(int,Size) for the minimum
-     * frame duration values.</p>
+     * <p>Refer to {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+     * for the minimum frame duration values.</p>
      * <p><b>Units</b>: Nanoseconds</p>
      * <p><b>Range of valid values:</b><br>
      * For FULL capability devices
@@ -2634,6 +2631,41 @@
             new Key<Integer>("android.sync.maxLatency", int.class);
 
     /**
+     * <p>The maximal camera capture pipeline stall (in unit of frame count) introduced by a
+     * reprocess capture request.</p>
+     * <p>The key describes the maximal interference that one reprocess (input) request
+     * can introduce to the camera simultaneous streaming of regular (output) capture
+     * requests, including repeating requests.</p>
+     * <p>When a reprocessing capture request is submitted while a camera output repeating request
+     * (e.g. preview) is being served by the camera device, it may preempt the camera capture
+     * pipeline for at least one frame duration so that the camera device is unable to process
+     * the following capture request in time for the next sensor start of exposure boundary.
+     * When this happens, the application may observe a capture time gap (longer than one frame
+     * duration) between adjacent capture output frames, which usually exhibits as preview
+     * glitch if the repeating request output targets include a preview surface. This key gives
+     * the worst-case number of frame stall introduced by one reprocess request with any kind of
+     * formats/sizes combination.</p>
+     * <p>If this key reports 0, it means a reprocess request doesn't introduce any glitch to the
+     * ongoing camera repeating request outputs, as if this reprocess request is never issued.</p>
+     * <p>This key is supported if the camera device supports OPAQUE or YUV reprocessing (
+     * i.e. {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains OPAQUE_REPROCESSING or
+     * YUV_REPROCESSING).</p>
+     * <p><b>Units</b>: Number of frames.</p>
+     * <p><b>Range of valid values:</b><br>
+     * &lt;= 4</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    @PublicKey
+    public static final Key<Integer> REPROCESS_MAX_CAPTURE_STALL =
+            new Key<Integer>("android.reprocess.maxCaptureStall", int.class);
+
+    /**
      * <p>The available depth dataspace stream
      * configurations that this camera device supports
      * (i.e. format, width, height, output/input stream).</p>
@@ -2672,8 +2704,7 @@
      * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
      * android.scaler.availableStallDurations for more details about
      * calculating the max frame rate.</p>
-     * <p>(Keep in sync with
-     * StreamConfigurationMap#getOutputMinFrameDuration)</p>
+     * <p>(Keep in sync with {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
@@ -2689,7 +2720,7 @@
 
     /**
      * <p>This lists the maximum stall duration for each
-     * format/size combination for depth streams.</p>
+     * output format/size combination for depth streams.</p>
      * <p>A stall duration is how much extra time would get added
      * to the normal minimum frame duration for a repeating request
      * that has streams with non-zero stall.</p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 51b326b..f6791a4 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -54,6 +54,7 @@
      * means that high frame rate is given priority over the highest-quality
      * post-processing. These requests would normally be used with the
      * {@link CameraCaptureSession#setRepeatingRequest} method.
+     * This template is guaranteed to be supported on all camera devices.
      *
      * @see #createCaptureRequest
      */
@@ -63,6 +64,7 @@
      * Create a request suitable for still image capture. Specifically, this
      * means prioritizing image quality over frame rate. These requests would
      * commonly be used with the {@link CameraCaptureSession#capture} method.
+     * This template is guaranteed to be supported on all camera devices.
      *
      * @see #createCaptureRequest
      */
@@ -73,6 +75,7 @@
      * that a stable frame rate is used, and post-processing is set for
      * recording quality. These requests would commonly be used with the
      * {@link CameraCaptureSession#setRepeatingRequest} method.
+     * This template is guaranteed to be supported on all camera devices.
      *
      * @see #createCaptureRequest
      */
@@ -84,6 +87,9 @@
      * disrupting the ongoing recording. These requests would commonly be used
      * with the {@link CameraCaptureSession#capture} method while a request based on
      * {@link #TEMPLATE_RECORD} is is in use with {@link CameraCaptureSession#setRepeatingRequest}.
+     * This template is guaranteed to be supported on all camera devices except
+     * legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY})
      *
      * @see #createCaptureRequest
      */
@@ -93,6 +99,11 @@
      * Create a request suitable for zero shutter lag still capture. This means
      * means maximizing image quality without compromising preview frame rate.
      * AE/AWB/AF should be on auto mode.
+     * This template is guaranteed to be supported on camera devices that support the
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING OPAQUE_REPROCESSING}
+     * capability or the
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}
+     * capability.
      *
      * @see #createCaptureRequest
      */
@@ -105,6 +116,9 @@
      * quality. The manual capture parameters (exposure, sensitivity, and so on)
      * are set to reasonable defaults, but should be overriden by the
      * application depending on the intended use case.
+     * This template is guaranteed to be supported on camera devices that support the
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR MANUAL_SENSOR}
+     * capability.
      *
      * @see #createCaptureRequest
      */
@@ -473,12 +487,14 @@
      * settings as desired, instead.</p>
      *
      * @param templateType An enumeration selecting the use case for this
-     * request; one of the CameraDevice.TEMPLATE_ values.
+     * request; one of the CameraDevice.TEMPLATE_ values. Not all template
+     * types are supported on every device. See the documentation for each
+     * template type for details.
      * @return a builder for a capture request, initialized with default
      * settings for that template, and no output streams
      *
-     * @throws IllegalArgumentException if the templateType is not in the list
-     * of supported templates.
+     * @throws IllegalArgumentException if the templateType is not supported by
+     * this device.
      * @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
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e3f1d73..ca9439b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -461,22 +461,21 @@
      * <p>The camera device supports the Zero Shutter Lag reprocessing use case.</p>
      * <ul>
      * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
-     * <li>ImageFormat#PRIVATE is supported as an output/input format, that is,
-     *   ImageFormat#PRIVATE is included in the lists of formats returned by
-     *   StreamConfigurationMap#getInputFormats and
-     *   StreamConfigurationMap#getOutputFormats.</li>
-     * <li>StreamConfigurationMap#getValidOutputFormatsForInput returns non empty int[] for
-     *   each supported input format returned by StreamConfigurationMap#getInputFormats.</li>
-     * <li>Each size returned by StreamConfigurationMap#getInputSizes(ImageFormat#PRIVATE)
-     *   is also included in StreamConfigurationMap#getOutputSizes(ImageFormat#PRIVATE)</li>
-     * <li>Using ImageFormat#PRIVATE does not cause a frame rate drop
-     *   relative to the sensor's maximum capture rate (at that
-     *   resolution).</li>
-     * <li>ImageFormat#PRIVATE will be reprocessable into both YUV_420_888
-     *   and JPEG formats.</li>
+     * <li>{@link android.graphics.ImageFormat#PRIVATE } is supported as an output/input format,
+     *   that is, {@link android.graphics.ImageFormat#PRIVATE } is included in the lists of
+     *   formats returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
+     * <li>{@link android.hardware.camera2.params.StreamConfigurationMap#getValidOutputFormatsForInput }
+     *   returns non empty int[] for each supported input format returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats }.</li>
+     * <li>Each size returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputSizes getInputSizes(ImageFormat.PRIVATE)} is also included in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes getOutputSizes(ImageFormat.PRIVATE)}</li>
+     * <li>Using {@link android.graphics.ImageFormat#PRIVATE } does not cause a frame rate drop
+     *   relative to the sensor's maximum capture rate (at that resolution).</li>
+     * <li>{@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into both
+     *   {@link android.graphics.ImageFormat#YUV_420_888 } and
+     *   {@link android.graphics.ImageFormat#JPEG } formats.</li>
      * <li>The maximum available resolution for OPAQUE streams
      *   (both input/output) will match the maximum available
      *   resolution of JPEG streams.</li>
+     * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
      * <li>Only below controls are effective for reprocessing requests and
      *   will be present in capture results, other controls in reprocess
      *   requests will be ignored by the camera device.<ul>
@@ -489,6 +488,7 @@
      *
      * @see CaptureRequest#EDGE_MODE
      * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL
      * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
@@ -569,25 +569,25 @@
      * following:</p>
      * <ul>
      * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
-     * <li>YUV_420_888 is supported as an output/input format, that is,
+     * <li>{@link android.graphics.ImageFormat#YUV_420_888 } is supported as an output/input format, that is,
      *   YUV_420_888 is included in the lists of formats returned by
-     *   StreamConfigurationMap#getInputFormats and
-     *   StreamConfigurationMap#getOutputFormats.</li>
-     * <li>StreamConfigurationMap#getValidOutputFormatsForInput returns non empty int[] for
-     *   each supported input format returned by StreamConfigurationMap#getInputFormats.</li>
-     * <li>Each size returned by StreamConfigurationMap#getInputSizes(YUV_420_888)
-     *   is also included in StreamConfigurationMap#getOutputSizes(YUV_420_888)</li>
-     * <li>Using YUV_420_888 does not cause a frame rate drop
+     *   {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and
+     *   {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
+     * <li>{@link android.hardware.camera2.params.StreamConfigurationMap#getValidOutputFormatsForInput }
+     *   returns non-empty int[] for each supported input format returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats }.</li>
+     * <li>Each size returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputSizes getInputSizes(YUV_420_888)} is also included in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes getOutputSizes(YUV_420_888)}</li>
+     * <li>Using {@link android.graphics.ImageFormat#YUV_420_888 } does not cause a frame rate drop
      *   relative to the sensor's maximum capture rate (at that resolution).</li>
-     * <li>YUV_420_888 will be reprocessable into both YUV_420_888
-     *   and JPEG formats.</li>
-     * <li>The maximum available resolution for YUV_420_888 streams
-     *   (both input/output) will match the maximum available
-     *   resolution of JPEG streams.</li>
-     * <li>Only the below controls are effective for reprocessing requests and will be
-     *   present in capture results. The reprocess requests are from the original capture
-     *   results that are assocaited with the intermidate YUV_420_888 output buffers.
-     *   All other controls in the reprocess requests will be ignored by the camera device.<ul>
+     * <li>{@link android.graphics.ImageFormat#YUV_420_888 } will be reprocessable into both
+     *   {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li>
+     * <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the
+     *   maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li>
+     * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
+     * <li>Only the below controls are effective for reprocessing requests and will be present
+     *   in capture results. The reprocess requests are from the original capture results that
+     *   are associated with the intermediate {@link android.graphics.ImageFormat#YUV_420_888 }
+     *   output buffers.  All other controls in the reprocess requests will be ignored by the
+     *   camera device.<ul>
      * <li>android.jpeg.*</li>
      * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
      * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
@@ -599,6 +599,7 @@
      * @see CaptureRequest#EDGE_MODE
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+     * @see CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL
      * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
@@ -608,11 +609,13 @@
      * <p>The camera device can produce depth measurements from its field of view.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
-     * <li>DEPTH16 is supported as an output format.</li>
-     * <li>DEPTH_POINT_CLOUD is optionally supported as an output format.</li>
-     * <li>This camera device, and all camera devices with the same android.lens.info.facing,
-     *   will list the following calibration entries in both CameraCharacteristics and
-     *   CaptureResults:<ul>
+     * <li>{@link android.graphics.ImageFormat#DEPTH16 } is supported as an output format.</li>
+     * <li>{@link android.graphics.ImageFormat#DEPTH_POINT_CLOUD } is optionally supported as an
+     *   output format.</li>
+     * <li>This camera device, and all camera devices with the same {@link CameraCharacteristics#LENS_FACING android.lens.facing},
+     *   will list the following calibration entries in both
+     *   {@link android.hardware.camera2.CameraCharacteristics } and
+     *   {@link android.hardware.camera2.CaptureResult }:<ul>
      * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
      * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
      * <li>android.lens.intrinsicCalibration</li>
@@ -627,13 +630,14 @@
      * <p>Generally, depth output operates at a slower frame rate than standard color capture,
      * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
      * should be accounted for (see
-     * android.hardware.camera2.StreamConfigurationMap#getOutputStallDuration).  On a device
-     * that supports both depth and color-based output, to enable smooth preview, using a
-     * repeating burst is recommended, where a depth-output target is only included once
-     * every N frames, where N is the ratio between preview output rate and depth output
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }).
+     * On a device that supports both depth and color-based output, to enable smooth preview,
+     * using a repeating burst is recommended, where a depth-output target is only included
+     * once every N frames, where N is the ratio between preview output rate and depth output
      * rate, including depth stall time.</p>
      *
      * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+     * @see CameraCharacteristics#LENS_FACING
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -707,7 +711,7 @@
 
     /**
      * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in the same timebase as
-     * android.os.SystemClock#elapsedRealtimeNanos(),
+     * {@link android.os.SystemClock#elapsedRealtimeNanos },
      * and they can be compared to other timestamps using that base.</p>
      *
      * @see CaptureResult#SENSOR_TIMESTAMP
@@ -866,7 +870,7 @@
     /**
      * <p>Every frame has the requests immediately applied.</p>
      * <p>Furthermore for all results,
-     * <code>android.sync.frameNumber == CaptureResult#getFrameNumber()</code></p>
+     * <code>android.sync.frameNumber == {@link android.hardware.camera2.CaptureResult#getFrameNumber }</code></p>
      * <p>Changing controls over multiple requests one after another will
      * produce results that have those controls applied atomically
      * each frame.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 19d17b1..ab6ce91 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1275,8 +1275,9 @@
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
      * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains MANUAL_SENSOR. Other intent values are always supported.</p>
+     * contains OPAQUE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are
+     * always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
@@ -2039,8 +2040,8 @@
      * cannot process more than 1 capture at a time.</li>
      * </ul>
      * <p>The necessary information for the application, given the model above,
-     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
-     * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
+     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
      * These are used to determine the maximum frame rate / minimum frame
      * duration that is possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
@@ -2049,21 +2050,19 @@
      * <ol>
      * <li>Let the set of currently configured input/output streams
      * be called <code>S</code>.</li>
-     * <li>Find the minimum frame durations for each stream in <code>S</code>, by
-     * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
-     * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
-     * its respective size/format). Let this set of frame durations be called
-     * <code>F</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
+     * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+     * (with its respective size/format). Let this set of frame durations be
+     * called <code>F</code>.</li>
      * <li>For any given request <code>R</code>, the minimum frame duration allowed
      * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
      * used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
-     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
-     * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
-     * respective size/format), then the frame duration in
-     * <code>F</code> determines the steady state frame rate that the application will
-     * get if it uses <code>R</code> as a repeating request. Let this special kind
-     * of request be called <code>Rsimple</code>.</p>
+     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
+     * using its respective size/format), then the frame duration in <code>F</code>
+     * determines the steady state frame rate that the application will get
+     * if it uses <code>R</code> as a repeating request. Let this special kind of
+     * request be called <code>Rsimple</code>.</p>
      * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
      * by a single capture of a new request <code>Rstall</code> (which has at least
      * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
@@ -2071,7 +2070,7 @@
      * if all buffers from the previous <code>Rstall</code> have already been
      * delivered.</p>
      * <p>For more details about stalling, see
-     * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: Nanoseconds</p>
@@ -2647,8 +2646,12 @@
      * <p><b>Range of valid values:</b><br>
      * &gt;= 1.0</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CaptureRequest#EDGE_MODE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ef5d75c..3dc8970 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1698,8 +1698,9 @@
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
      * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains MANUAL_SENSOR. Other intent values are always supported.</p>
+     * contains OPAQUE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are
+     * always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
@@ -2885,8 +2886,8 @@
      * cannot process more than 1 capture at a time.</li>
      * </ul>
      * <p>The necessary information for the application, given the model above,
-     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
-     * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
+     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
      * These are used to determine the maximum frame rate / minimum frame
      * duration that is possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
@@ -2895,21 +2896,19 @@
      * <ol>
      * <li>Let the set of currently configured input/output streams
      * be called <code>S</code>.</li>
-     * <li>Find the minimum frame durations for each stream in <code>S</code>, by
-     * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
-     * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
-     * its respective size/format). Let this set of frame durations be called
-     * <code>F</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
+     * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+     * (with its respective size/format). Let this set of frame durations be
+     * called <code>F</code>.</li>
      * <li>For any given request <code>R</code>, the minimum frame duration allowed
      * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
      * used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
-     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
-     * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
-     * respective size/format), then the frame duration in
-     * <code>F</code> determines the steady state frame rate that the application will
-     * get if it uses <code>R</code> as a repeating request. Let this special kind
-     * of request be called <code>Rsimple</code>.</p>
+     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
+     * using its respective size/format), then the frame duration in <code>F</code>
+     * determines the steady state frame rate that the application will get
+     * if it uses <code>R</code> as a repeating request. Let this special kind of
+     * request be called <code>Rsimple</code>.</p>
      * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
      * by a single capture of a new request <code>Rstall</code> (which has at least
      * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
@@ -2917,7 +2916,7 @@
      * if all buffers from the previous <code>Rstall</code> have already been
      * delivered.</p>
      * <p>For more details about stalling, see
-     * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: Nanoseconds</p>
@@ -2979,11 +2978,10 @@
      * and are monotonically increasing. They can be compared with the
      * timestamps for other captures from the same camera device, but are
      * not guaranteed to be comparable to any other time source.</p>
-     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} <code>==</code> REALTIME,
-     * the timestamps measure time in the same timebase as
-     * android.os.SystemClock#elapsedRealtimeNanos(), and they can be
-     * compared to other timestamps from other subsystems that are using
-     * that base.</p>
+     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} <code>==</code> REALTIME, the
+     * timestamps measure time in the same timebase as {@link android.os.SystemClock#elapsedRealtimeNanos }, and they can
+     * be compared to other timestamps from other subsystems that
+     * are using that base.</p>
      * <p><b>Units</b>: Nanoseconds</p>
      * <p><b>Range of valid values:</b><br>
      * &gt; 0</p>
@@ -3141,7 +3139,7 @@
      * <p><b>Units</b>: Nanoseconds</p>
      * <p><b>Range of valid values:</b><br>
      * &gt;= 0 and &lt;
-     * StreamConfigurationMap#getOutputMinFrameDuration(int, Size).</p>
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -3966,8 +3964,12 @@
      * <p><b>Range of valid values:</b><br>
      * &gt;= 1.0</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CaptureRequest#EDGE_MODE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index abe26ea..edad00f 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -202,6 +202,7 @@
         private static final int CAMERA_IDLE = 1;
         private static final int CAPTURE_STARTED = 2;
         private static final int RESULT_RECEIVED = 3;
+        private static final int PREPARED = 4;
 
         private final HandlerThread mHandlerThread;
         private Handler mHandler;
@@ -253,7 +254,9 @@
 
         @Override
         public void onPrepared(int streamId) {
-            // TODO
+            Message msg = getHandler().obtainMessage(PREPARED,
+                    /*arg1*/ streamId, /*arg2*/ 0);
+            getHandler().sendMessage(msg);
         }
 
         @Override
@@ -301,6 +304,11 @@
                             mCallbacks.onResultReceived(result, resultExtras);
                             break;
                         }
+                        case PREPARED: {
+                            int streamId = msg.arg1;
+                            mCallbacks.onPrepared(streamId);
+                            break;
+                        }
                         default:
                             throw new IllegalArgumentException(
                                 "Unknown callback message " + msg.what);
@@ -631,7 +639,9 @@
             return CameraBinderDecorator.ENODEV;
         }
 
-        // TODO: Implement and fire callback
+        // LEGACY doesn't support actual prepare, just signal success right away
+        mCameraCallbacks.onPrepared(streamId);
+
         return CameraBinderDecorator.NO_ERROR;
     }
 
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index adab9be..02793f1 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -182,6 +182,10 @@
         // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
         public float screenAutoBrightnessAdjustment;
 
+        // Set to true if screenBrightness and screenAutoBrightnessAdjustment were both
+        // set by the user as opposed to being programmatically controlled by apps.
+        public boolean brightnessSetByUser;
+
         // If true, enables automatic brightness control.
         public boolean useAutoBrightness;
 
@@ -229,6 +233,7 @@
             useProximitySensor = other.useProximitySensor;
             screenBrightness = other.screenBrightness;
             screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
+            brightnessSetByUser = other.brightnessSetByUser;
             useAutoBrightness = other.useAutoBrightness;
             blockScreenOn = other.blockScreenOn;
             lowPowerMode = other.lowPowerMode;
@@ -249,6 +254,7 @@
                     && useProximitySensor == other.useProximitySensor
                     && screenBrightness == other.screenBrightness
                     && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
+                    && brightnessSetByUser == other.brightnessSetByUser
                     && useAutoBrightness == other.useAutoBrightness
                     && blockScreenOn == other.blockScreenOn
                     && lowPowerMode == other.lowPowerMode
@@ -268,6 +274,7 @@
                     + ", useProximitySensor=" + useProximitySensor
                     + ", screenBrightness=" + screenBrightness
                     + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+                    + ", brightnessSetByUser=" + brightnessSetByUser
                     + ", useAutoBrightness=" + useAutoBrightness
                     + ", blockScreenOn=" + blockScreenOn
                     + ", lowPowerMode=" + lowPowerMode
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2257b0a..cf96145 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -42,6 +42,7 @@
 import java.util.List;
 
 import javax.crypto.Cipher;
+import javax.crypto.Mac;
 
 /**
  * A class that coordinates access to the fingerprint hardware.
@@ -195,18 +196,26 @@
 
     /**
      * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
-     * framework supports {@link Signature} and {@link Cipher} objects.
+     * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
      */
     public static class CryptoObject {
 
-        public CryptoObject(Signature signature) {
+        public CryptoObject(@NonNull Signature signature) {
             mSignature = signature;
             mCipher = null;
+            mMac = null;
         }
 
-        public CryptoObject(Cipher cipher) {
+        public CryptoObject(@NonNull Cipher cipher) {
             mCipher = cipher;
             mSignature = null;
+            mMac = null;
+        }
+
+        public CryptoObject(@NonNull Mac mac) {
+            mMac = mac;
+            mCipher = null;
+            mSignature = null;
         }
 
         /**
@@ -222,6 +231,12 @@
         public Cipher getCipher() { return mCipher; }
 
         /**
+         * Get {@link Mac} object.
+         * @return {@link Mac} object or null if this doesn't contain one.
+         */
+        public Mac getMac() { return mMac; }
+
+        /**
          * @hide
          * @return the opId associated with this object or 0 if none
          */
@@ -230,12 +245,15 @@
                 return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature);
             } else if (mCipher != null) {
                 return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher);
+            } else if (mMac != null) {
+                return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac);
             }
             return 0;
         }
 
         private final Signature mSignature;
         private final Cipher mCipher;
+        private final Mac mMac;
     };
 
     /**
@@ -416,7 +434,8 @@
             mAuthenticationCallback = callback;
             mCryptoObject = crypto;
             long sessionId = crypto != null ? crypto.getOpId() : 0;
-            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags);
+            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception while authenticating: ", e);
             if (callback != null) {
@@ -537,7 +556,7 @@
      */
     public List<Fingerprint> getEnrolledFingerprints(int userId) {
         if (mService != null) try {
-            return mService.getEnrolledFingerprints(userId);
+            return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
         }
@@ -561,7 +580,8 @@
      */
     public boolean hasEnrolledFingerprints() {
         if (mService != null) try {
-            return mService.hasEnrolledFingerprints(UserHandle.myUserId());
+            return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
         }
@@ -577,7 +597,7 @@
         if (mService != null) {
             try {
                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
-                return mService.isHardwareDetected(deviceId);
+                return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
             }
@@ -596,7 +616,7 @@
     public long getAuthenticatorId() {
         if (mService != null) {
             try {
-                return mService.getAuthenticatorId();
+                return mService.getAuthenticatorId(mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
             }
@@ -606,7 +626,13 @@
         return 0;
     }
 
-    private Handler mHandler = new Handler() {
+    private Handler mHandler;
+
+    private class MyHandler extends Handler {
+        private MyHandler(Context context) {
+            super(context.getMainLooper());
+        }
+
         public void handleMessage(android.os.Message msg) {
             switch(msg.what) {
                 case MSG_ENROLL_RESULT:
@@ -691,6 +717,7 @@
         if (mService == null) {
             Slog.v(TAG, "FingerprintManagerService was null");
         }
+        mHandler = new MyHandler(context);
     }
 
     private int getCurrentUserId() {
@@ -718,7 +745,7 @@
 
     private void cancelAuthentication(CryptoObject cryptoObject) {
         if (mService != null) try {
-            mService.cancelAuthentication(mToken);
+            mService.cancelAuthentication(mToken, mContext.getOpPackageName());
         } catch (RemoteException e) {
             if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
         }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index c5ec08c..0484806 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -27,10 +27,10 @@
 interface IFingerprintService {
     // Authenticate the given sessionId with a fingerprint
     void authenticate(IBinder token, long sessionId, int groupId,
-            IFingerprintServiceReceiver receiver, int flags);
+            IFingerprintServiceReceiver receiver, int flags, String opPackageName);
 
     // Cancel authentication for the given sessionId
-    void cancelAuthentication(IBinder token);
+    void cancelAuthentication(IBinder token, String opPackageName);
 
     // Start fingerprint enrollment
     void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
@@ -46,16 +46,16 @@
     void rename(int fingerId, int groupId, String name);
 
     // Get a list of enrolled fingerprints in the given group.
-    List<Fingerprint> getEnrolledFingerprints(int groupId);
+    List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName);
 
     // Determine if HAL is loaded and ready
-    boolean isHardwareDetected(long deviceId);
+    boolean isHardwareDetected(long deviceId, String opPackageName);
 
     // Get a pre-enrollment authentication token
     long preEnroll(IBinder token);
 
     // Determine if a user has at least one enrolled fingerprint
-    boolean hasEnrolledFingerprints(int groupId);
+    boolean hasEnrolledFingerprints(int groupId, String opPackageName);
 
     // Gets the number of hardware devices
     // int getHardwareDeviceCount();
@@ -64,5 +64,5 @@
     // long getHardwareDevice(int i);
 
     // Gets the authenticator ID for fingerprint
-    long getAuthenticatorId();
+    long getAuthenticatorId(String opPackageName);
 }
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 1a42319..410d550 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -45,6 +45,7 @@
     private final String mName;
     private final String mManufacturerName;
     private final String mProductName;
+    private final String mVersion;
     private final String mSerialNumber;
     private final int mVendorId;
     private final int mProductId;
@@ -62,7 +63,7 @@
      */
     public UsbDevice(String name, int vendorId, int productId,
             int Class, int subClass, int protocol,
-            String manufacturerName, String productName, String serialNumber) {
+            String manufacturerName, String productName, String version, String serialNumber) {
         mName = name;
         mVendorId = vendorId;
         mProductId = productId;
@@ -71,6 +72,7 @@
         mProtocol = protocol;
         mManufacturerName = manufacturerName;
         mProductName = productName;
+        mVersion = version;
         mSerialNumber = serialNumber;
     }
 
@@ -104,6 +106,15 @@
     }
 
     /**
+     * Returns the version number of the device.
+     *
+     * @return the device version
+     */
+    public String getVersion() {
+        return mVersion;
+    }
+
+    /**
      * Returns the serial number of the device.
      *
      * @return the serial number name
@@ -263,7 +274,7 @@
                 ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
                 ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
                 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
-                ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
+                ",mVersion=" + mVersion + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
         for (int i = 0; i < mConfigurations.length; i++) {
             builder.append("\n");
             builder.append(mConfigurations[i].toString());
@@ -283,10 +294,11 @@
             int protocol = in.readInt();
             String manufacturerName = in.readString();
             String productName = in.readString();
+            String version = in.readString();
             String serialNumber = in.readString();
             Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader());
             UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
-                                 manufacturerName, productName, serialNumber);
+                                 manufacturerName, productName, version, serialNumber);
             device.setConfigurations(configurations);
             return device;
         }
@@ -309,6 +321,7 @@
         parcel.writeInt(mProtocol);
         parcel.writeString(mManufacturerName);
         parcel.writeString(mProductName);
+        parcel.writeString(mVersion);
         parcel.writeString(mSerialNumber);
         parcel.writeParcelableArray(mConfigurations, 0);
    }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c531e7e..2d63e3f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -341,7 +341,8 @@
      * one.  This is used by applications needing to talk to the carrier's
      * Multimedia Messaging Service servers.
      *
-     * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+     * @deprecated Applications should instead use
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
      *         provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability.
      */
     public static final int TYPE_MOBILE_MMS  = 2;
@@ -351,7 +352,8 @@
      * one.  This is used by applications needing to talk to the carrier's
      * Secure User Plane Location servers for help locating the device.
      *
-     * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+     * @deprecated Applications should instead use
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
      *         provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability.
      */
     public static final int TYPE_MOBILE_SUPL = 3;
@@ -367,7 +369,8 @@
      * same network interface as {@link #TYPE_MOBILE} but the routing setup
      * is different.
      *
-     * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+     * @deprecated Applications should instead use
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
      *         uses the {@link NetworkCapabilities#TRANSPORT_CELLULAR} transport.
      */
     public static final int TYPE_MOBILE_HIPRI = 5;
@@ -910,7 +913,8 @@
      * implementation+feature combination, except that the value {@code -1}
      * always indicates failure.
      *
-     * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
+     * @deprecated Deprecated in favor of the cleaner
+     *             {@link #requestNetwork(NetworkRequest, NetworkCallback)} API.
      * @removed
      */
     public int startUsingNetworkFeature(int networkType, String feature) {
@@ -958,7 +962,7 @@
      * implementation+feature combination, except that the value {@code -1}
      * always indicates failure.
      *
-     * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
+     * @deprecated Deprecated in favor of the cleaner {@link unregisterNetworkCallback} API.
      * @removed
      */
     public int stopUsingNetworkFeature(int networkType, String feature) {
@@ -1236,8 +1240,9 @@
      * @param hostAddress the IP address of the host to which the route is desired
      * @return {@code true} on success, {@code false} on failure
      *
-     * @deprecated Deprecated in favor of the {@link #requestNetwork},
-     *             {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} api.
+     * @deprecated Deprecated in favor of the
+     *             {@link #requestNetwork(NetworkRequest, NetworkCallback)},
+     *             {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API.
      * @removed
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -1256,7 +1261,7 @@
      * @return {@code true} on success, {@code false} on failure
      * @hide
      * @deprecated Deprecated in favor of the {@link #requestNetwork} and
-     *             {@link #bindProcessToNetwork} api.
+     *             {@link #bindProcessToNetwork} API.
      * @removed
      */
     public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
@@ -2144,14 +2149,22 @@
         public static final int CANCELED     = 8;
 
         /**
-         * @hide
-         * Called whenever the framework connects to a network that it may use to
-         * satisfy this request
+         * Called when the framework connects to a new network to evaluate whether it satisfies this
+         * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
+         * callback. There is no guarantee that this new network will satisfy any requests, or that
+         * the network will stay connected for longer than the time necessary to evaluate it.
+         * <p>
+         * Most applications <b>should not</b> act on this callback, and should instead use
+         * {@link #onAvailable}. This callback is intended for use by applications that can assist
+         * the framework in properly evaluating the network &mdash; for example, an application that
+         * can automatically log in to a captive portal without user intervention.
+         *
+         * @param network The {@link Network} of the network that is being evaluated.
          */
         public void onPreCheck(Network network) {}
 
         /**
-         * Called when the framework connects and has declared new network ready for use.
+         * Called when the framework connects and has declared a new network ready for use.
          * This callback may be called more than once if the {@link Network} that is
          * satisfying the request changes.
          *
@@ -2251,116 +2264,82 @@
         @Override
         public void handleMessage(Message message) {
             Log.d(TAG, "CM callback handler got msg " + message.what);
+            NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
+            Network network = (Network) getObject(message, Network.class);
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        callbacks.onPreCheck((Network)getObject(message, Network.class));
-                    } else {
-                        Log.e(TAG, "callback not found for PRECHECK message");
+                    NetworkCallback callback = getCallback(request, "PRECHECK");
+                    if (callback != null) {
+                        callback.onPreCheck(network);
                     }
                     break;
                 }
                 case CALLBACK_AVAILABLE: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        callbacks.onAvailable((Network)getObject(message, Network.class));
-                    } else {
-                        Log.e(TAG, "callback not found for AVAILABLE message");
+                    NetworkCallback callback = getCallback(request, "AVAILABLE");
+                    if (callback != null) {
+                        callback.onAvailable(network);
                     }
                     break;
                 }
                 case CALLBACK_LOSING: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        callbacks.onLosing((Network)getObject(message, Network.class),
-                                message.arg1);
-                    } else {
-                        Log.e(TAG, "callback not found for LOSING message");
+                    NetworkCallback callback = getCallback(request, "LOSING");
+                    if (callback != null) {
+                        callback.onLosing(network, message.arg1);
                     }
                     break;
                 }
                 case CALLBACK_LOST: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        callbacks.onLost((Network)getObject(message, Network.class));
-                    } else {
-                        Log.e(TAG, "callback not found for LOST message");
+                    NetworkCallback callback = getCallback(request, "LOST");
+                    if (callback != null) {
+                        callback.onLost(network);
                     }
                     break;
                 }
                 case CALLBACK_UNAVAIL: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = null;
-                    synchronized(mCallbackMap) {
-                        callbacks = mCallbackMap.get(request);
-                    }
-                    if (callbacks != null) {
-                        callbacks.onUnavailable();
-                    } else {
-                        Log.e(TAG, "callback not found for UNAVAIL message");
+                    NetworkCallback callback = getCallback(request, "UNAVAIL");
+                    if (callback != null) {
+                        callback.onUnavailable();
                     }
                     break;
                 }
                 case CALLBACK_CAP_CHANGED: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        Network network = (Network)getObject(message, Network.class);
+                    NetworkCallback callback = getCallback(request, "CAP_CHANGED");
+                    if (callback != null) {
                         NetworkCapabilities cap = (NetworkCapabilities)getObject(message,
                                 NetworkCapabilities.class);
 
-                        callbacks.onCapabilitiesChanged(network, cap);
-                    } else {
-                        Log.e(TAG, "callback not found for CAP_CHANGED message");
+                        callback.onCapabilitiesChanged(network, cap);
                     }
                     break;
                 }
                 case CALLBACK_IP_CHANGED: {
-                    NetworkRequest request = (NetworkRequest)getObject(message,
-                            NetworkRequest.class);
-                    NetworkCallback callbacks = getCallbacks(request);
-                    if (callbacks != null) {
-                        Network network = (Network)getObject(message, Network.class);
+                    NetworkCallback callback = getCallback(request, "IP_CHANGED");
+                    if (callback != null) {
                         LinkProperties lp = (LinkProperties)getObject(message,
                                 LinkProperties.class);
 
-                        callbacks.onLinkPropertiesChanged(network, lp);
-                    } else {
-                        Log.e(TAG, "callback not found for IP_CHANGED message");
+                        callback.onLinkPropertiesChanged(network, lp);
                     }
                     break;
                 }
                 case CALLBACK_RELEASED: {
-                    NetworkRequest req = (NetworkRequest)getObject(message, NetworkRequest.class);
-                    NetworkCallback callbacks = null;
+                    NetworkCallback callback = null;
                     synchronized(mCallbackMap) {
-                        callbacks = mCallbackMap.remove(req);
+                        callback = mCallbackMap.remove(request);
                     }
-                    if (callbacks != null) {
+                    if (callback != null) {
                         synchronized(mRefCount) {
                             if (mRefCount.decrementAndGet() == 0) {
                                 getLooper().quit();
                             }
                         }
                     } else {
-                        Log.e(TAG, "callback not found for CANCELED message");
+                        Log.e(TAG, "callback not found for RELEASED message");
                     }
                     break;
                 }
                 case CALLBACK_EXIT: {
-                    Log.d(TAG, "Listener quiting");
+                    Log.d(TAG, "Listener quitting");
                     getLooper().quit();
                     break;
                 }
@@ -2374,10 +2353,16 @@
         private Object getObject(Message msg, Class c) {
             return msg.getData().getParcelable(c.getSimpleName());
         }
-        private NetworkCallback getCallbacks(NetworkRequest req) {
+
+        private NetworkCallback getCallback(NetworkRequest req, String name) {
+            NetworkCallback callback;
             synchronized(mCallbackMap) {
-                return mCallbackMap.get(req);
+                callback = mCallbackMap.get(req);
             }
+            if (callback == null) {
+                Log.e(TAG, "callback not found for " + name + " message");
+            }
+            return callback;
         }
     }
 
@@ -2601,10 +2586,10 @@
 
     /**
      * Unregisters callbacks about and possibly releases networks originating from
-     * {@link #requestNetwork} and {@link #registerNetworkCallback} calls.  If the
-     * given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
-     * any networks that had been connected to only to satisfy that request will be
-     * disconnected.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and {@link #registerNetworkCallback}
+     * calls.  If the given {@code NetworkCallback} had previously been used with
+     * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
+     * will be disconnected.
      *
      * @param networkCallback The {@link NetworkCallback} used when making the request.
      */
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index c722fbc..7f5f377 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -38,8 +38,6 @@
 
     boolean isUidForeground(int uid);
 
-    int[] getPowerSaveAppIdWhitelist();
-
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8c8bfab..ab70485 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -37,6 +37,11 @@
      * @hide
      */
     public NetworkCapabilities() {
+        clearAll();
+        mNetworkCapabilities =
+                (1 << NET_CAPABILITY_NOT_RESTRICTED) |
+                (1 << NET_CAPABILITY_TRUSTED) |
+                (1 << NET_CAPABILITY_NOT_VPN);
     }
 
     public NetworkCapabilities(NetworkCapabilities nc) {
@@ -50,11 +55,21 @@
     }
 
     /**
+     * Completely clears the contents of this object, removing even the capabilities that are set
+     * by default when the object is constructed.
+     * @hide
+     */
+    public void clearAll() {
+        mNetworkCapabilities = mTransportTypes = 0;
+        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
+        mNetworkSpecifier = null;
+    }
+
+    /**
      * Represents the network's capabilities.  If any are specified they will be satisfied
      * by any Network that matches all of them.
      */
-    private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED) |
-            (1 << NET_CAPABILITY_TRUSTED) | (1 << NET_CAPABILITY_NOT_VPN);
+    private long mNetworkCapabilities;
 
     /**
      * Indicates this is a network that has the ability to reach the
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index bc03637..ecc3fb4 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -41,6 +41,7 @@
  */
 public class NetworkPolicyManager {
 
+    /* POLICY_* are masks and can be ORed */
     /** No specific network policy, use system default. */
     public static final int POLICY_NONE = 0x0;
     /** Reject network usage on metered networks when application in background. */
@@ -48,10 +49,17 @@
     /** Allow network use (metered or not) in the background in battery save mode. */
     public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
+    /* RULE_* are not masks and they must be exclusive */
     /** All network traffic should be allowed. */
     public static final int RULE_ALLOW_ALL = 0x0;
     /** Reject traffic on metered networks. */
     public static final int RULE_REJECT_METERED = 0x1;
+    /** Reject traffic on all networks. */
+    public static final int RULE_REJECT_ALL = 0x2;
+
+    public static final int FIREWALL_RULE_DEFAULT = 0;
+    public static final int FIREWALL_RULE_ALLOW = 1;
+    public static final int FIREWALL_RULE_DENY = 2;
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
@@ -80,7 +88,7 @@
      * Set policy flags for specific UID.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
-     * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -129,14 +137,6 @@
         }
     }
 
-    public int[] getPowerSaveAppIdWhitelist() {
-        try {
-            return mService.getPowerSaveAppIdWhitelist();
-        } catch (RemoteException e) {
-            return new int[0];
-        }
-    }
-
     public void registerListener(INetworkPolicyListener listener) {
         try {
             mService.registerListener(listener);
@@ -330,6 +330,8 @@
         fout.write("[");
         if ((rules & RULE_REJECT_METERED) != 0) {
             fout.write("REJECT_METERED");
+        } else if ((rules & RULE_REJECT_ALL) != 0) {
+            fout.write("REJECT_ALL");
         }
         fout.write("]");
     }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index f305b2a..4a8dfbc 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1657,7 +1657,7 @@
     /**
      * Searches the query string for the first value with the given key.
      *
-     * <p><strong>Warning:</strong> Prior to Ice Cream Sandwich, this decoded
+     * <p><strong>Warning:</strong> Prior to Jelly Bean, this decoded
      * the '+' character as '+' rather than ' '.
      *
      * @param key which will be encoded
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 2eb97f1..8e0584a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.File;
@@ -242,6 +243,15 @@
         return DATA_DIRECTORY;
     }
 
+    /** {@hide} */
+    public static File getDataAppDirectory(String volumeUuid) {
+        if (TextUtils.isEmpty(volumeUuid)) {
+            return new File("/data/app");
+        } else {
+            return new File("/mnt/expand/" + volumeUuid + "/app");
+        }
+    }
+
     /**
      * Return the primary external storage directory. This directory may not
      * currently be accessible if it has been mounted by the user on their
@@ -758,7 +768,6 @@
      * @hide
      */
     public static File maybeTranslateEmulatedPathToInternal(File path) {
-        // TODO: bring back this optimization
-        return path;
+        return StorageManager.maybeTranslateEmulatedPathToInternal(path);
     }
 }
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 931cd3e..021e5e4 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -390,7 +390,7 @@
      * attacks.
      */
     public static boolean contains(File dir, File file) {
-        if (file == null) return false;
+        if (dir == null || file == null) return false;
 
         String dirPath = dir.getAbsolutePath();
         String filePath = file.getAbsolutePath();
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
new file mode 100644
index 0000000..3cb29ff
--- /dev/null
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** @hide */
+interface IDeviceIdleController {
+    void addPowerSaveWhitelistApp(String name);
+    void removePowerSaveWhitelistApp(String name);
+    String[] getSystemPowerWhitelist();
+    String[] getFullPowerWhitelist();
+    int[] getAppIdWhitelist();
+}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f93550a..b29e8d0 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -342,7 +342,7 @@
     void setFirewallInterfaceRule(String iface, boolean allow);
     void setFirewallEgressSourceRule(String addr, boolean allow);
     void setFirewallEgressDestRule(String addr, int port, boolean allow);
-    void setFirewallUidRule(int uid, boolean allow);
+    void setFirewallUidRule(int uid, int rule);
 
     /**
      * Set all packets from users in ranges to go through VPN specified by netId.
diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl
index 73a68f1..0cc1603 100644
--- a/core/java/android/os/IPermissionController.aidl
+++ b/core/java/android/os/IPermissionController.aidl
@@ -20,4 +20,5 @@
 /** @hide */
 interface IPermissionController {
     boolean checkPermission(String permission, int pid, int uid);
+    String[] getPackagesForUid(int uid);
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 01c9a21..1d9d7d2 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -920,6 +920,14 @@
             = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
 
     /**
+     * @hide Intent that is broadcast when the set of power save whitelist apps has changed.
+     * This broadcast is only sent to registered receivers.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_POWER_SAVE_WHITELIST_CHANGED
+            = "android.os.action.POWER_SAVE_WHITELIST_CHANGED";
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
      * This broadcast is only sent to registered receivers.
      *
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 355ec8c..009649f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -634,6 +634,9 @@
             if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) {
                 argsForZygote.add("--enable-jit");
             }
+            if ((debugFlags & Zygote.DEBUG_GENERATE_CFI) != 0) {
+                argsForZygote.add("--generate-cfi");
+            }
             if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                 argsForZygote.add("--enable-assert");
             }
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 16e0bf7..fcde3f4 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -942,6 +942,24 @@
             }
 
             @Override
+            public VolumeRecord[] getVolumeRecords(int _flags) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                VolumeRecord[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(_flags);
+                    mRemote.transact(Stub.TRANSACTION_getVolumeRecords, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.createTypedArray(VolumeRecord.CREATOR);
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            @Override
             public void mount(String volId) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
@@ -1033,12 +1051,12 @@
             }
 
             @Override
-            public void setVolumeNickname(String volId, String nickname) throws RemoteException {
+            public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(volId);
+                    _data.writeString(fsUuid);
                     _data.writeString(nickname);
                     mRemote.transact(Stub.TRANSACTION_setVolumeNickname, _data, _reply, 0);
                     _reply.readException();
@@ -1049,12 +1067,12 @@
             }
 
             @Override
-            public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException {
+            public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(volId);
+                    _data.writeString(fsUuid);
                     _data.writeInt(flags);
                     _data.writeInt(mask);
                     mRemote.transact(Stub.TRANSACTION_setVolumeUserFlags, _data, _reply, 0);
@@ -1066,6 +1084,21 @@
             }
 
             @Override
+            public void forgetVolume(String fsUuid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(fsUuid);
+                    mRemote.transact(Stub.TRANSACTION_forgetVolume, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
             public String getPrimaryStorageUuid() throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
@@ -1192,20 +1225,22 @@
 
         static final int TRANSACTION_getDisks = IBinder.FIRST_CALL_TRANSACTION + 44;
         static final int TRANSACTION_getVolumes = IBinder.FIRST_CALL_TRANSACTION + 45;
+        static final int TRANSACTION_getVolumeRecords = IBinder.FIRST_CALL_TRANSACTION + 46;
 
-        static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 46;
-        static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 47;
-        static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 48;
+        static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 47;
+        static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 48;
+        static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 49;
 
-        static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 49;
-        static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 50;
-        static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 51;
+        static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 50;
+        static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 51;
+        static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 52;
 
-        static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 52;
-        static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 53;
+        static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 53;
+        static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 54;
+        static final int TRANSACTION_forgetVolume = IBinder.FIRST_CALL_TRANSACTION + 55;
 
-        static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 54;
-        static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 55;
+        static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 56;
+        static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57;
 
         /**
          * Cast an IBinder object into an IMountService interface, generating a
@@ -1647,6 +1682,14 @@
                     reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     return true;
                 }
+                case TRANSACTION_getVolumeRecords: {
+                    data.enforceInterface(DESCRIPTOR);
+                    int _flags = data.readInt();
+                    VolumeRecord[] volumes = getVolumeRecords(_flags);
+                    reply.writeNoException();
+                    reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+                    return true;
+                }
                 case TRANSACTION_mount: {
                     data.enforceInterface(DESCRIPTOR);
                     String volId = data.readString();
@@ -1707,6 +1750,13 @@
                     reply.writeNoException();
                     return true;
                 }
+                case TRANSACTION_forgetVolume: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String fsUuid = data.readString();
+                    forgetVolume(fsUuid);
+                    reply.writeNoException();
+                    return true;
+                }
                 case TRANSACTION_getPrimaryStorageUuid: {
                     data.enforceInterface(DESCRIPTOR);
                     String volumeUuid = getPrimaryStorageUuid();
@@ -2012,6 +2062,7 @@
 
     public DiskInfo[] getDisks() throws RemoteException;
     public VolumeInfo[] getVolumes(int flags) throws RemoteException;
+    public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException;
 
     public void mount(String volId) throws RemoteException;
     public void unmount(String volId) throws RemoteException;
@@ -2021,8 +2072,9 @@
     public void partitionPrivate(String diskId) throws RemoteException;
     public void partitionMixed(String diskId, int ratio) throws RemoteException;
 
-    public void setVolumeNickname(String volId, String nickname) throws RemoteException;
-    public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException;
+    public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException;
+    public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException;
+    public void forgetVolume(String fsUuid) throws RemoteException;
 
     public String getPrimaryStorageUuid() throws RemoteException;
     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java
index fcb4779..c958fb0 100644
--- a/core/java/android/os/storage/IMountServiceListener.java
+++ b/core/java/android/os/storage/IMountServiceListener.java
@@ -91,10 +91,17 @@
                     reply.writeNoException();
                     return true;
                 }
-                case TRANSACTION_onVolumeMetadataChanged: {
+                case TRANSACTION_onVolumeRecordChanged: {
                     data.enforceInterface(DESCRIPTOR);
-                    final VolumeInfo vol = (VolumeInfo) data.readParcelable(null);
-                    onVolumeMetadataChanged(vol);
+                    final VolumeRecord rec = (VolumeRecord) data.readParcelable(null);
+                    onVolumeRecordChanged(rec);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_onVolumeForgotten: {
+                    data.enforceInterface(DESCRIPTOR);
+                    final String fsUuid = data.readString();
+                    onVolumeForgotten(fsUuid);
                     reply.writeNoException();
                     return true;
                 }
@@ -192,13 +199,29 @@
             }
 
             @Override
-            public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException {
+            public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeParcelable(vol, 0);
-                    mRemote.transact(Stub.TRANSACTION_onVolumeMetadataChanged, _data, _reply,
+                    _data.writeParcelable(rec, 0);
+                    mRemote.transact(Stub.TRANSACTION_onVolumeRecordChanged, _data, _reply,
+                            android.os.IBinder.FLAG_ONEWAY);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void onVolumeForgotten(String fsUuid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(fsUuid);
+                    mRemote.transact(Stub.TRANSACTION_onVolumeForgotten, _data, _reply,
                             android.os.IBinder.FLAG_ONEWAY);
                     _reply.readException();
                 } finally {
@@ -228,8 +251,9 @@
         static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0);
         static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1);
         static final int TRANSACTION_onVolumeStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 2);
-        static final int TRANSACTION_onVolumeMetadataChanged = (IBinder.FIRST_CALL_TRANSACTION + 3);
-        static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 4);
+        static final int TRANSACTION_onVolumeRecordChanged = (IBinder.FIRST_CALL_TRANSACTION + 3);
+        static final int TRANSACTION_onVolumeForgotten = (IBinder.FIRST_CALL_TRANSACTION + 4);
+        static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 5);
     }
 
     /**
@@ -252,8 +276,8 @@
 
     public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)
             throws RemoteException;
-
-    public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException;
+    public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException;
+    public void onVolumeForgotten(String fsUuid) throws RemoteException;
 
     public void onDiskScanned(DiskInfo disk, int volumeCount) throws RemoteException;
 }
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 6a0140e..214c60d 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -41,7 +41,10 @@
     public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
     }
 
-    public void onVolumeMetadataChanged(VolumeInfo vol) {
+    public void onVolumeRecordChanged(VolumeRecord rec) {
+    }
+
+    public void onVolumeForgotten(String fsUuid) {
     }
 
     public void onDiskScanned(DiskInfo disk, int volumeCount) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 6116aef..50e7d1c4 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -34,6 +34,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.os.SomeArgs;
@@ -79,9 +80,6 @@
     /** {@hide} */
     public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
 
-    /** {@hide} */
-    public static final int FLAG_ALL_METADATA = 1 << 0;
-
     private final Context mContext;
     private final ContentResolver mResolver;
 
@@ -95,8 +93,9 @@
             Handler.Callback {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;
-        private static final int MSG_VOLUME_METADATA_CHANGED = 3;
-        private static final int MSG_DISK_SCANNED = 4;
+        private static final int MSG_VOLUME_RECORD_CHANGED = 3;
+        private static final int MSG_VOLUME_FORGOTTEN = 4;
+        private static final int MSG_DISK_SCANNED = 5;
 
         final StorageEventListener mCallback;
         final Handler mHandler;
@@ -119,8 +118,12 @@
                     mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
                     args.recycle();
                     return true;
-                case MSG_VOLUME_METADATA_CHANGED:
-                    mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
+                case MSG_VOLUME_RECORD_CHANGED:
+                    mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
+                    args.recycle();
+                    return true;
+                case MSG_VOLUME_FORGOTTEN:
+                    mCallback.onVolumeForgotten((String) args.arg1);
                     args.recycle();
                     return true;
                 case MSG_DISK_SCANNED:
@@ -156,10 +159,17 @@
         }
 
         @Override
-        public void onVolumeMetadataChanged(VolumeInfo vol) {
+        public void onVolumeRecordChanged(VolumeRecord rec) {
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = vol;
-            mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
+            args.arg1 = rec;
+            mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
+        }
+
+        @Override
+        public void onVolumeForgotten(String fsUuid) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = fsUuid;
+            mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
         }
 
         @Override
@@ -248,8 +258,9 @@
     }
 
     /** {@hide} */
+    @Deprecated
     public static StorageManager from(Context context) {
-        return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+        return context.getSystemService(StorageManager.class);
     }
 
     /**
@@ -516,6 +527,18 @@
     }
 
     /** {@hide} */
+    public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
+        Preconditions.checkNotNull(fsUuid);
+        // TODO; go directly to service to make this faster
+        for (VolumeRecord rec : getVolumeRecords()) {
+            if (Objects.equals(rec.fsUuid, fsUuid)) {
+                return rec;
+            }
+        }
+        return null;
+    }
+
+    /** {@hide} */
     public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
         return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
     }
@@ -526,14 +549,29 @@
     }
 
     /** {@hide} */
-    public @NonNull List<VolumeInfo> getVolumes() {
-        return getVolumes(0);
+    public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
+        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
+            return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
+        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
+            return getPrimaryPhysicalVolume();
+        } else {
+            return findVolumeByUuid(volumeUuid);
+        }
     }
 
     /** {@hide} */
-    public @NonNull List<VolumeInfo> getVolumes(int flags) {
+    public @NonNull List<VolumeInfo> getVolumes() {
         try {
-            return Arrays.asList(mMountService.getVolumes(flags));
+            return Arrays.asList(mMountService.getVolumes(0));
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public @NonNull List<VolumeRecord> getVolumeRecords() {
+        try {
+            return Arrays.asList(mMountService.getVolumeRecords(0));
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -541,13 +579,25 @@
 
     /** {@hide} */
     public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
-        String descrip = vol.getDescription();
-        if (vol.disk != null) {
-            if (TextUtils.isEmpty(descrip)) {
-                descrip = vol.disk.getDescription();
+        if (vol == null) return null;
+
+        // Nickname always takes precedence when defined
+        if (!TextUtils.isEmpty(vol.fsUuid)) {
+            final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
+            if (!TextUtils.isEmpty(rec.nickname)) {
+                return rec.nickname;
             }
         }
-        return descrip;
+
+        if (!TextUtils.isEmpty(vol.getDescription())) {
+            return vol.getDescription();
+        }
+
+        if (vol.disk != null) {
+            return vol.disk.getDescription();
+        }
+
+        return null;
     }
 
     /** {@hide} */
@@ -616,29 +666,62 @@
     }
 
     /** {@hide} */
-    public void setVolumeNickname(String volId, String nickname) {
+    public void wipeAdoptableDisks() {
+        // We only wipe devices in "adoptable" locations, which are in a
+        // long-term stable slot/location on the device, where apps have a
+        // reasonable chance of storing sensitive data. (Apps need to go through
+        // SAF to write to transient volumes.)
+        final List<DiskInfo> disks = getDisks();
+        for (DiskInfo disk : disks) {
+            final String diskId = disk.getId();
+            if (disk.isAdoptable()) {
+                Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
+                try {
+                    // TODO: switch to explicit wipe command when we have it,
+                    // for now rely on the fact that vfat format does a wipe
+                    mMountService.partitionPublic(diskId);
+                } catch (Exception e) {
+                    Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
+                }
+            } else {
+                Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
+            }
+        }
+    }
+
+    /** {@hide} */
+    public void setVolumeNickname(String fsUuid, String nickname) {
         try {
-            mMountService.setVolumeNickname(volId, nickname);
+            mMountService.setVolumeNickname(fsUuid, nickname);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /** {@hide} */
-    public void setVolumeInited(String volId, boolean inited) {
+    public void setVolumeInited(String fsUuid, boolean inited) {
         try {
-            mMountService.setVolumeUserFlags(volId, inited ? VolumeInfo.USER_FLAG_INITED : 0,
-                    VolumeInfo.USER_FLAG_INITED);
+            mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
+                    VolumeRecord.USER_FLAG_INITED);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /** {@hide} */
-    public void setVolumeSnoozed(String volId, boolean snoozed) {
+    public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
         try {
-            mMountService.setVolumeUserFlags(volId, snoozed ? VolumeInfo.USER_FLAG_SNOOZED : 0,
-                    VolumeInfo.USER_FLAG_SNOOZED);
+            mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
+                    VolumeRecord.USER_FLAG_SNOOZED);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void forgetVolume(String fsUuid) {
+        try {
+            mMountService.forgetVolume(fsUuid);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -804,6 +887,27 @@
                 DEFAULT_FULL_THRESHOLD_BYTES);
     }
 
+    /** {@hide} */
+    public static File maybeTranslateEmulatedPathToInternal(File path) {
+        final IMountService mountService = IMountService.Stub.asInterface(
+                ServiceManager.getService("mount"));
+        try {
+            final VolumeInfo[] vols = mountService.getVolumes(0);
+            for (VolumeInfo vol : vols) {
+                if ((vol.getType() == VolumeInfo.TYPE_EMULATED
+                        || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
+                    final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(),
+                            vol.getInternalPath(), path);
+                    if (internalPath != null) {
+                        return internalPath;
+                    }
+                }
+            }
+        } catch (RemoteException ignored) {
+        }
+        return path;
+    }
+
     /// Consts to match the password types in cryptfs.h
     /** @hide */
     public static final int CRYPT_TYPE_PASSWORD = 0;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 4e9cfc7..2622ee0 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -78,9 +78,6 @@
     public static final int MOUNT_FLAG_PRIMARY = 1 << 0;
     public static final int MOUNT_FLAG_VISIBLE = 1 << 1;
 
-    public static final int USER_FLAG_INITED = 1 << 0;
-    public static final int USER_FLAG_SNOOZED = 1 << 1;
-
     private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
     private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
 
@@ -132,11 +129,10 @@
     public String fsUuid;
     public String fsLabel;
     public String path;
+    public String internalPath;
 
     /** Framework state */
     public final int mtpIndex;
-    public String nickname;
-    public int userFlags = 0;
 
     public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) {
         this.id = Preconditions.checkNotNull(id);
@@ -160,9 +156,8 @@
         fsUuid = parcel.readString();
         fsLabel = parcel.readString();
         path = parcel.readString();
+        internalPath = parcel.readString();
         mtpIndex = parcel.readInt();
-        nickname = parcel.readString();
-        userFlags = parcel.readInt();
     }
 
     public static @NonNull String getEnvironmentForState(int state) {
@@ -210,10 +205,6 @@
         return fsUuid;
     }
 
-    public @Nullable String getNickname() {
-        return nickname;
-    }
-
     public int getMountUserId() {
         return mountUserId;
     }
@@ -221,8 +212,6 @@
     public @Nullable String getDescription() {
         if (ID_PRIVATE_INTERNAL.equals(id)) {
             return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
-        } else if (!TextUtils.isEmpty(nickname)) {
-            return nickname;
         } else if (!TextUtils.isEmpty(fsLabel)) {
             return fsLabel;
         } else {
@@ -250,14 +239,6 @@
         return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
     }
 
-    public boolean isInited() {
-        return (userFlags & USER_FLAG_INITED) != 0;
-    }
-
-    public boolean isSnoozed() {
-        return (userFlags & USER_FLAG_SNOOZED) != 0;
-    }
-
     public boolean isVisibleToUser(int userId) {
         if (type == TYPE_PUBLIC && userId == this.mountUserId) {
             return isVisible();
@@ -269,7 +250,11 @@
     }
 
     public File getPath() {
-        return new File(path);
+        return (path != null) ? new File(path) : null;
+    }
+
+    public File getInternalPath() {
+        return (internalPath != null) ? new File(internalPath) : null;
     }
 
     public File getPathForUser(int userId) {
@@ -356,14 +341,11 @@
         final Uri uri;
         if (type == VolumeInfo.TYPE_PUBLIC) {
             uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
-        } else if (VolumeInfo.ID_EMULATED_INTERNAL.equals(id)) {
+        } else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) {
             uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
                     DOCUMENT_ROOT_PRIMARY_EMULATED);
-        } else if (type == VolumeInfo.TYPE_EMULATED) {
-            // TODO: build intent once supported
-            uri = null;
         } else {
-            throw new IllegalArgumentException();
+            return null;
         }
 
         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
@@ -393,9 +375,8 @@
         pw.printPair("fsLabel", fsLabel);
         pw.println();
         pw.printPair("path", path);
+        pw.printPair("internalPath", internalPath);
         pw.printPair("mtpIndex", mtpIndex);
-        pw.printPair("nickname", nickname);
-        pw.printPair("userFlags", DebugUtils.flagsToString(getClass(), "USER_FLAG_", userFlags));
         pw.decreaseIndent();
         pw.println();
     }
@@ -460,8 +441,7 @@
         parcel.writeString(fsUuid);
         parcel.writeString(fsLabel);
         parcel.writeString(path);
+        parcel.writeString(internalPath);
         parcel.writeInt(mtpIndex);
-        parcel.writeString(nickname);
-        parcel.writeInt(userFlags);
     }
 }
diff --git a/core/java/android/os/storage/VolumeRecord.java b/core/java/android/os/storage/VolumeRecord.java
new file mode 100644
index 0000000..096e2dd
--- /dev/null
+++ b/core/java/android/os/storage/VolumeRecord.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DebugUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Metadata for a storage volume which may not be currently present.
+ *
+ * @hide
+ */
+public class VolumeRecord implements Parcelable {
+    public static final String EXTRA_FS_UUID =
+            "android.os.storage.extra.FS_UUID";
+
+    public static final int USER_FLAG_INITED = 1 << 0;
+    public static final int USER_FLAG_SNOOZED = 1 << 1;
+
+    public final int type;
+    public final String fsUuid;
+    public String nickname;
+    public int userFlags;
+
+    public VolumeRecord(int type, String fsUuid) {
+        this.type = type;
+        this.fsUuid = Preconditions.checkNotNull(fsUuid);
+    }
+
+    public VolumeRecord(Parcel parcel) {
+        type = parcel.readInt();
+        fsUuid = parcel.readString();
+        nickname = parcel.readString();
+        userFlags = parcel.readInt();
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public String getFsUuid() {
+        return fsUuid;
+    }
+
+    public String getNickname() {
+        return nickname;
+    }
+
+    public boolean isInited() {
+        return (userFlags & USER_FLAG_INITED) != 0;
+    }
+
+    public boolean isSnoozed() {
+        return (userFlags & USER_FLAG_SNOOZED) != 0;
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("VolumeRecord:");
+        pw.increaseIndent();
+        pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type));
+        pw.printPair("fsUuid", fsUuid);
+        pw.printPair("nickname", nickname);
+        pw.printPair("userFlags",
+                DebugUtils.flagsToString(VolumeRecord.class, "USER_FLAG_", userFlags));
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    @Override
+    public VolumeRecord clone() {
+        final Parcel temp = Parcel.obtain();
+        try {
+            writeToParcel(temp, 0);
+            temp.setDataPosition(0);
+            return CREATOR.createFromParcel(temp);
+        } finally {
+            temp.recycle();
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof VolumeRecord) {
+            return Objects.equals(fsUuid, ((VolumeRecord) o).fsUuid);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return fsUuid.hashCode();
+    }
+
+    public static final Creator<VolumeRecord> CREATOR = new Creator<VolumeRecord>() {
+        @Override
+        public VolumeRecord createFromParcel(Parcel in) {
+            return new VolumeRecord(in);
+        }
+
+        @Override
+        public VolumeRecord[] newArray(int size) {
+            return new VolumeRecord[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(type);
+        parcel.writeString(fsUuid);
+        parcel.writeString(nickname);
+        parcel.writeInt(userFlags);
+    }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 00c851b..293cf6f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -919,6 +919,15 @@
             = "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
 
     /**
+     * Activity Action: Show Zen Mode event rule configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_EVENT_RULE_SETTINGS
+            = "android.settings.ZEN_MODE_EVENT_RULE_SETTINGS";
+
+    /**
      * Activity Action: Show Zen Mode external rule configuration settings.
      *
      * @hide
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index b3a3aad..03248e5 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -87,6 +87,28 @@
         return result;
     }
 
+    public Long getLong(int tag) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getLong(tag, -1);
+        } else if (swEnforced.containsTag(tag)) {
+            return swEnforced.getLong(tag, -1);
+        } else {
+            return null;
+        }
+    }
+
+    public long getLong(int tag, long defaultValue) {
+        Long result = getLong(tag);
+        return (result != null) ? result : defaultValue;
+    }
+
+    public List<Long> getLongs(int tag) {
+        List<Long> result = new ArrayList<Long>();
+        result.addAll(hwEnforced.getLongs(tag));
+        result.addAll(swEnforced.getLongs(tag));
+        return result;
+    }
+
     public Date getDate(int tag) {
         Date result = hwEnforced.getDate(tag, null);
         if (result == null) {
@@ -105,11 +127,11 @@
         }
     }
 
-    public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
-        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
-            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+    public boolean getBoolean(int tag) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getBoolean(tag, false);
         } else {
-            return keyCharacteristics.swEnforced.getBoolean(tag, false);
+            return swEnforced.getBoolean(tag, false);
         }
     }
 }
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 40baf9c..0e2b8ba 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -194,6 +194,9 @@
     public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
     public static final int KM_ERROR_MISSING_NONCE = -51;
     public static final int KM_ERROR_INVALID_NONCE = -52;
+    public static final int KM_ERROR_UNSUPPORTED_CHUNK_LENGTH = -53;
+    public static final int KM_ERROR_RESCOPABLE_KEY_NOT_USABLE = -54;
+    public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -235,6 +238,8 @@
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
         sErrorCodeToString.put(KM_ERROR_MISSING_NONCE, "Required IV missing");
         sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
+        sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED,
+                "Caller-provided IV not permitted");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 14e947c..f09f4d2 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -62,7 +62,7 @@
             Calendar.WEDNESDAY, Calendar.THURSDAY };
     public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY };
 
-    public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+    public static final int[] MINUTE_BUCKETS = generateMinuteBuckets();
     private static final int SECONDS_MS = 1000;
     private static final int MINUTES_MS = 60 * SECONDS_MS;
     private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
@@ -95,7 +95,7 @@
     private static final String MANUAL_TAG = "manual";
     private static final String AUTOMATIC_TAG = "automatic";
 
-    private static final String RULE_ATT_ID = "id";
+    private static final String RULE_ATT_ID = "ruleId";
     private static final String RULE_ATT_ENABLED = "enabled";
     private static final String RULE_ATT_SNOOZING = "snoozing";
     private static final String RULE_ATT_NAME = "name";
@@ -201,6 +201,18 @@
         }
     }
 
+    private static int[] generateMinuteBuckets() {
+        final int maxHrs = 12;
+        final int[] buckets = new int[maxHrs + 3];
+        buckets[0] = 15;
+        buckets[1] = 30;
+        buckets[2] = 45;
+        for (int i = 1; i <= maxHrs; i++) {
+            buckets[2 + i] = 60 * i;
+        }
+        return buckets;
+    }
+
     public static String sourceToString(int source) {
         switch (source) {
             case SOURCE_ANYONE:
@@ -267,6 +279,15 @@
         }
     }
 
+    private static long tryParseLong(String value, long defValue) {
+        if (TextUtils.isEmpty(value)) return defValue;
+        try {
+            return Long.valueOf(value);
+        } catch (NumberFormatException e) {
+            return defValue;
+        }
+    }
+
     public static ZenModeConfig readXml(XmlPullParser parser, Migration migration)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
@@ -298,10 +319,10 @@
                         throw new IndexOutOfBoundsException("bad source in config:" + rt.allowFrom);
                     }
                 } else if (MANUAL_TAG.equals(tag)) {
-                    rt.manualRule = readRuleXml(parser);
+                    rt.manualRule = readRuleXml(parser, false /*conditionRequired*/);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
                     final String id = parser.getAttributeValue(null, RULE_ATT_ID);
-                    final ZenRule automaticRule = readRuleXml(parser);
+                    final ZenRule automaticRule = readRuleXml(parser, true /*conditionRequired*/);
                     if (id != null && automaticRule != null) {
                         rt.automaticRules.put(id, automaticRule);
                     }
@@ -341,7 +362,7 @@
         out.endTag(null, ZEN_TAG);
     }
 
-    public static ZenRule readRuleXml(XmlPullParser parser) {
+    public static ZenRule readRuleXml(XmlPullParser parser, boolean conditionRequired) {
         final ZenRule rt = new ZenRule();
         rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
         rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false);
@@ -355,7 +376,7 @@
         rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
         rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
         rt.condition = readConditionXml(parser);
-        return rt.condition != null ? rt : null;
+        return rt;
     }
 
     public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
@@ -556,10 +577,12 @@
                 Condition.FLAG_RELEVANT_NOW);
     }
 
-    // For built-in conditions
+    // ==== Built-in system conditions ====
+
     public static final String SYSTEM_AUTHORITY = "android";
 
-    // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
+    // ==== Built-in system condition: countdown ====
+
     public static final String COUNTDOWN_PATH = "countdown";
 
     public static Uri toCountdownConditionId(long time) {
@@ -586,9 +609,43 @@
         return tryParseCountdownConditionId(conditionId) != 0;
     }
 
-    // built-in schedule conditions
+    // ==== Built-in system condition: schedule ====
+
     public static final String SCHEDULE_PATH = "schedule";
 
+    public static Uri toScheduleConditionId(ScheduleInfo schedule) {
+        return new Uri.Builder().scheme(Condition.SCHEME)
+                .authority(SYSTEM_AUTHORITY)
+                .appendPath(SCHEDULE_PATH)
+                .appendQueryParameter("days", toDayList(schedule.days))
+                .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
+                .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
+                .build();
+    }
+
+    public static boolean isValidScheduleConditionId(Uri conditionId) {
+        return tryParseScheduleConditionId(conditionId) != null;
+    }
+
+    public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
+        final boolean isSchedule =  conditionId != null
+                && conditionId.getScheme().equals(Condition.SCHEME)
+                && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+                && conditionId.getPathSegments().size() == 1
+                && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
+        if (!isSchedule) return null;
+        final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
+        final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
+        if (start == null || end == null) return null;
+        final ScheduleInfo rt = new ScheduleInfo();
+        rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\.");
+        rt.startHour = start[0];
+        rt.startMinute = start[1];
+        rt.endHour = end[0];
+        rt.endMinute = end[1];
+        return rt;
+    }
+
     public static class ScheduleInfo {
         public int[] days;
         public int startHour;
@@ -626,39 +683,76 @@
         }
     }
 
-    public static Uri toScheduleConditionId(ScheduleInfo schedule) {
+    // ==== Built-in system condition: event ====
+
+    public static final String EVENT_PATH = "event";
+
+    public static Uri toEventConditionId(EventInfo event) {
         return new Uri.Builder().scheme(Condition.SCHEME)
                 .authority(SYSTEM_AUTHORITY)
-                .appendPath(SCHEDULE_PATH)
-                .appendQueryParameter("days", toDayList(schedule.days))
-                .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
-                .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
+                .appendPath(EVENT_PATH)
+                .appendQueryParameter("calendar", Long.toString(event.calendar))
+                .appendQueryParameter("attendance", Integer.toString(event.attendance))
+                .appendQueryParameter("reply", Integer.toString(event.reply))
                 .build();
     }
 
-    public static boolean isValidScheduleConditionId(Uri conditionId) {
-        return tryParseScheduleConditionId(conditionId) != null;
+    public static boolean isValidEventConditionId(Uri conditionId) {
+        return tryParseEventConditionId(conditionId) != null;
     }
 
-    public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
-        final boolean isSchedule =  conditionId != null
+    public static EventInfo tryParseEventConditionId(Uri conditionId) {
+        final boolean isEvent = conditionId != null
                 && conditionId.getScheme().equals(Condition.SCHEME)
                 && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
                 && conditionId.getPathSegments().size() == 1
-                && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
-        if (!isSchedule) return null;
-        final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
-        final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
-        if (start == null || end == null) return null;
-        final ScheduleInfo rt = new ScheduleInfo();
-        rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\.");
-        rt.startHour = start[0];
-        rt.startMinute = start[1];
-        rt.endHour = end[0];
-        rt.endMinute = end[1];
+                && conditionId.getPathSegments().get(0).equals(EVENT_PATH);
+        if (!isEvent) return null;
+        final EventInfo rt = new EventInfo();
+        rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"), 0L);
+        rt.attendance = tryParseInt(conditionId.getQueryParameter("attendance"), 0);
+        rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0);
         return rt;
     }
 
+    public static class EventInfo {
+        public static final int ATTENDANCE_REQUIRED_OR_OPTIONAL = 0;
+        public static final int ATTENDANCE_REQUIRED = 1;
+        public static final int ATTENDANCE_OPTIONAL = 2;
+
+        public static final int REPLY_ANY = 0;
+        public static final int REPLY_ANY_EXCEPT_NO = 1;
+        public static final int REPLY_YES = 2;
+
+        public long calendar;  // CalendarContract.Calendars._ID, or 0 for any
+        public int attendance;
+        public int reply;
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof EventInfo)) return false;
+            final EventInfo other = (EventInfo) o;
+            return calendar == other.calendar
+                    && attendance == other.attendance
+                    && reply == other.reply;
+        }
+
+        public EventInfo copy() {
+            final EventInfo rt = new EventInfo();
+            rt.calendar = calendar;
+            rt.attendance = attendance;
+            rt.reply = reply;
+            return rt;
+        }
+    }
+
+    // ==== End built-in system conditions ====
+
     private static int[] tryParseHourAndMinute(String value) {
         if (TextUtils.isEmpty(value)) return null;
         final int i = value.indexOf('.');
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index e991d84..ce94315c 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -403,4 +403,12 @@
      */
     public static final String EXTRA_SUPPORTED_LANGUAGES =
             "android.speech.extra.SUPPORTED_LANGUAGES";
+
+    /**
+     * Optional boolean, to be used with {@link #ACTION_RECOGNIZE_SPEECH},
+     * {@link #ACTION_VOICE_SEARCH_HANDS_FREE}, {@link #ACTION_WEB_SEARCH} to indicate whether to
+     * only use an offline speech recognition engine. The default is false, meaning that either
+     * network or offline recognition engines may be used.
+     */
+    public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
 }
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index a7d9503..ca37d49 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -214,7 +214,7 @@
                         sConstructors.put(className, constructor);
                     }
                 }
-
+                constructor.setAccessible(true);
                 return constructor.newInstance(mContext, attrs);
             }
         } catch (InstantiationException e) {
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index aefced8..558b8f5 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -74,6 +74,7 @@
         private static final byte LONG_TYPE   = 1;
         private static final byte STRING_TYPE = 2;
         private static final byte LIST_TYPE   = 3;
+        private static final byte FLOAT_TYPE = 4;
 
         /** @param data containing event, read from the system */
         /*package*/ Event(byte[] data) {
@@ -106,7 +107,7 @@
             return mBuffer.getInt(offset);
         }
 
-        /** @return one of Integer, Long, String, null, or Object[] of same. */
+        /** @return one of Integer, Long, Float, String, null, or Object[] of same. */
         public synchronized Object getData() {
             try {
                 int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
@@ -130,10 +131,13 @@
             byte type = mBuffer.get();
             switch (type) {
             case INT_TYPE:
-                return (Integer) mBuffer.getInt();
+                return mBuffer.getInt();
 
             case LONG_TYPE:
-                return (Long) mBuffer.getLong();
+                return mBuffer.getLong();
+
+            case FLOAT_TYPE:
+                return mBuffer.getFloat();
 
             case STRING_TYPE:
                 try {
@@ -180,6 +184,14 @@
     /**
      * Record an event log message.
      * @param tag The event type tag code
+     * @param value A value to log
+     * @return The number of bytes written
+     */
+    public static native int writeEvent(int tag, float value);
+
+    /**
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param str A value to log
      * @return The number of bytes written
      */
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index eedbc70..46dd857 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -234,25 +234,13 @@
      * Draws the specified display list onto this canvas. The display list can only
      * be drawn if {@link android.view.RenderNode#isValid()} returns true.
      *
-     * @param renderNode The RenderNode to replay.
+     * @param renderNode The RenderNode to draw.
      */
     public void drawRenderNode(RenderNode renderNode) {
-        drawRenderNode(renderNode, RenderNode.FLAG_CLIP_CHILDREN);
+        nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList());
     }
 
-    /**
-     * Draws the specified display list onto this canvas.
-     *
-     * @param renderNode The RenderNode to replay.
-     * @param flags Optional flags about drawing, see {@link RenderNode} for
-     *              the possible flags.
-     */
-    public void drawRenderNode(RenderNode renderNode, int flags) {
-        nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList(), flags);
-    }
-
-    private static native void nDrawRenderNode(long renderer, long renderNode,
-            int flags);
+    private static native void nDrawRenderNode(long renderer, long renderNode);
 
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index cc090ad5..6651b83 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -52,6 +52,11 @@
     public static final int CALENDAR_DATE = 5;
 
     /**
+     * The user has touched the screen with a stylus and pressed the stylus button.
+     */
+    public static final int STYLUS_BUTTON_PRESS = 6;
+
+    /**
      * This is a private constant.  Feel free to renumber as desired.
      * @hide
      */
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 457d6ad..1503728 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -946,25 +946,21 @@
                                 attrs, R.styleable.Include);
                         final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
                         final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                        final boolean hasWidth = a.hasValue(R.styleable.Include_layout_width);
-                        final boolean hasHeight = a.hasValue(R.styleable.Include_layout_height);
                         a.recycle();
 
-                        // We try to load the layout params set in the <include /> tag. If
-                        // they don't exist, we will rely on the layout params set in the
-                        // included XML file.
-                        // During a layoutparams generation, a runtime exception is thrown
-                        // if either layout_width or layout_height is missing. We catch
-                        // this exception and set localParams accordingly: true means we
-                        // successfully loaded layout params from the <include /> tag,
-                        // false means we need to rely on the included layout params.
+                        // We try to load the layout params set in the <include /> tag.
+                        // If the parent can't generate layout params (ex. missing width
+                        // or height for the framework ViewGroups, though this is not
+                        // necessarily true of all ViewGroups) then we expect it to throw
+                        // a runtime exception.
+                        // We catch this exception and set localParams accordingly: true
+                        // means we successfully loaded layout params from the <include>
+                        // tag, false means we need to rely on the included layout params.
                         ViewGroup.LayoutParams params = null;
-                        if (hasWidth && hasHeight) {
-                            try {
-                                params = group.generateLayoutParams(attrs);
-                            } catch (RuntimeException e) {
-                                // Ignore, just fail over to child attrs.
-                            }
+                        try {
+                            params = group.generateLayoutParams(attrs);
+                        } catch (RuntimeException e) {
+                            // Ignore, just fail over to child attrs.
                         }
                         if (params == null) {
                             params = group.generateLayoutParams(childAttrs);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 5e45c8f..5df596a 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3180,6 +3180,18 @@
         return (getButtonState() & button) == button;
     }
 
+    /**
+     * Checks if a stylus is being used and if the first stylus button is
+     * pressed.
+     *
+     * @return True if the tool is a stylus and if the first stylus button is
+     *         pressed.
+     * @see #BUTTON_SECONDARY
+     */
+    public final boolean isStylusButtonPressed() {
+        return (isButtonPressed(BUTTON_SECONDARY) && getToolType(0) == TOOL_TYPE_STYLUS);
+    }
+
     public static final Parcelable.Creator<MotionEvent> CREATOR
             = new Parcelable.Creator<MotionEvent>() {
         public MotionEvent createFromParcel(Parcel in) {
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 794c8e7..a3e7a10 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -3599,7 +3599,7 @@
         if (!mForcedNavigationBarColor) {
             mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
         }
-        if (a.getBoolean(R.styleable.Window_windowHasLightStatusBar, false)) {
+        if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
             decor.setSystemUiVisibility(
                     decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
         }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index ad34f02..85b22fb 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -246,6 +246,9 @@
             mSurface = null;
             mLayer = null;
 
+            // Make sure if/when new layer gets re-created, transform matrix will
+            // be re-applied.
+            mMatrixChanged = true;
             mHadSurface = true;
         }
     }
@@ -284,11 +287,6 @@
         return LAYER_TYPE_HARDWARE;
     }
 
-    @Override
-    boolean hasStaticLayer() {
-        return true;
-    }
-
     /**
      * Calling this method has no effect.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 87d5d9a..5017a38 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -360,7 +360,7 @@
     @Override
     boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
         return nCopyLayerInto(mNativeProxy,
-                layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
+                layer.getDeferredLayerUpdater(), bitmap);
     }
 
     @Override
@@ -531,7 +531,7 @@
 
     private static native long nCreateTextureLayer(long nativeProxy);
     private static native void nBuildLayer(long nativeProxy, long node);
-    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
     private static native void nPushLayerUpdate(long nativeProxy, long layer);
     private static native void nCancelLayerUpdate(long nativeProxy, long layer);
     private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7da2da4..81ad5ad 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -30,6 +30,7 @@
 import android.annotation.Size;
 import android.content.ClipData;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -986,6 +987,17 @@
      */
     static final int DUPLICATE_PARENT_STATE = 0x00400000;
 
+    /**
+     * <p>
+     * Indicates this view can be stylus button pressed. When stylus button
+     * pressable, a View reacts to stylus button presses by notifiying
+     * the OnStylusButtonPressListener.
+     * </p>
+     * {@hide}
+     */
+    static final int STYLUS_BUTTON_PRESSABLE = 0x00800000;
+
+
     /** @hide */
     @IntDef({
         SCROLLBARS_INSIDE_OVERLAY,
@@ -2591,7 +2603,7 @@
      * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS
      *         FLAG_TRANSLUCENT_STATUS}.
      *
-     * @see android.R.attr#windowHasLightStatusBar
+     * @see android.R.attr#windowLightStatusBar
      */
     public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
 
@@ -3269,6 +3281,13 @@
         protected OnLongClickListener mOnLongClickListener;
 
         /**
+         * Listener used to dispatch stylus touch and button press events. This field should be made
+         * private, so it is hidden from the SDK.
+         * {@hide}
+         */
+        protected OnStylusButtonPressListener mOnStylusButtonPressListener;
+
+        /**
          * Listener used to build the context menu.
          * This field should be made private, so it is hidden from the SDK.
          * {@hide}
@@ -3359,6 +3378,13 @@
     private boolean mHasPerformedLongPress;
 
     /**
+     * Whether the stylus button is currently pressed down. This is true when
+     * the stylus is touching the screen and the button has been pressed, this
+     * is false once the stylus has been lifted.
+     */
+    private boolean mInStylusButtonPress = false;
+
+    /**
      * The minimum height of the view. We'll try our best to have the height
      * of this view to at least this amount.
      */
@@ -3874,6 +3900,12 @@
                         viewFlagMasks |= LONG_CLICKABLE;
                     }
                     break;
+                case com.android.internal.R.styleable.View_stylusButtonPressable:
+                    if (a.getBoolean(attr, false)) {
+                        viewFlagValues |= STYLUS_BUTTON_PRESSABLE;
+                        viewFlagMasks |= STYLUS_BUTTON_PRESSABLE;
+                    }
+                    break;
                 case com.android.internal.R.styleable.View_saveEnabled:
                     if (!a.getBoolean(attr, true)) {
                         viewFlagValues |= SAVE_DISABLED;
@@ -4016,37 +4048,7 @@
 
                     final String handlerName = a.getString(attr);
                     if (handlerName != null) {
-                        setOnClickListener(new OnClickListener() {
-                            private Method mHandler;
-
-                            public void onClick(View v) {
-                                if (mHandler == null) {
-                                    try {
-                                        mHandler = getContext().getClass().getMethod(handlerName,
-                                                View.class);
-                                    } catch (NoSuchMethodException e) {
-                                        int id = getId();
-                                        String idText = id == NO_ID ? "" : " with id '"
-                                                + getContext().getResources().getResourceEntryName(
-                                                    id) + "'";
-                                        throw new IllegalStateException("Could not find a method " +
-                                                handlerName + "(View) in the activity "
-                                                + getContext().getClass() + " for onClick handler"
-                                                + " on view " + View.this.getClass() + idText, e);
-                                    }
-                                }
-
-                                try {
-                                    mHandler.invoke(getContext(), View.this);
-                                } catch (IllegalAccessException e) {
-                                    throw new IllegalStateException("Could not execute non "
-                                            + "public method of the activity", e);
-                                } catch (InvocationTargetException e) {
-                                    throw new IllegalStateException("Could not execute "
-                                            + "method of the activity", e);
-                                }
-                            }
-                        });
+                        setOnClickListener(new DeclaredOnClickListener(this, handlerName));
                     }
                     break;
                 case R.styleable.View_overScrollMode:
@@ -4238,6 +4240,66 @@
     }
 
     /**
+     * An implementation of OnClickListener that attempts to lazily load a
+     * named click handling method from a parent or ancestor context.
+     */
+    private static class DeclaredOnClickListener implements OnClickListener {
+        private final View mHostView;
+        private final String mMethodName;
+
+        private Method mMethod;
+
+        public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
+            mHostView = hostView;
+            mMethodName = methodName;
+        }
+
+        @Override
+        public void onClick(@NonNull View v) {
+            if (mMethod == null) {
+                mMethod = resolveMethod(mHostView.getContext(), mMethodName);
+            }
+
+            try {
+                mMethod.invoke(mHostView.getContext(), v);
+            } catch (IllegalAccessException e) {
+                throw new IllegalStateException(
+                        "Could not execute non-public method for android:onClick", e);
+            } catch (InvocationTargetException e) {
+                throw new IllegalStateException(
+                        "Could not execute method for android:onClick", e);
+            }
+        }
+
+        @NonNull
+        private Method resolveMethod(@Nullable Context context, @NonNull String name) {
+            while (context != null) {
+                try {
+                    if (!context.isRestricted()) {
+                        return context.getClass().getMethod(mMethodName, View.class);
+                    }
+                } catch (NoSuchMethodException e) {
+                    // Failed to find method, keep searching up the hierarchy.
+                }
+
+                if (context instanceof ContextWrapper) {
+                    context = ((ContextWrapper) context).getBaseContext();
+                } else {
+                    // Can't search up the hierarchy, null out and fail.
+                    context = null;
+                }
+            }
+
+            final int id = mHostView.getId();
+            final String idText = id == NO_ID ? "" : " with id '"
+                    + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
+            throw new IllegalStateException("Could not find method " + mMethodName
+                    + "(View) in a parent or ancestor Context for android:onClick "
+                    + "attribute defined on view " + mHostView.getClass() + idText);
+        }
+    }
+
+    /**
      * Non-public constructor for use in testing
      */
     View() {
@@ -4309,6 +4371,7 @@
         out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.');
         out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.');
         out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.');
+        out.append((mViewFlags & STYLUS_BUTTON_PRESSABLE) != 0 ? 'S' : '.');
         out.append(' ');
         out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.');
         out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.');
@@ -4804,6 +4867,20 @@
     }
 
     /**
+     * Register a callback to be invoked when this view is touched with a stylus and the button is
+     * pressed.
+     *
+     * @param l The callback that will run
+     * @see #setStylusButtonPressable(boolean)
+     */
+    public void setOnStylusButtonPressListener(@Nullable OnStylusButtonPressListener l) {
+        if (!isStylusButtonPressable()) {
+            setStylusButtonPressable(true);
+        }
+        getListenerInfo().mOnStylusButtonPressListener = l;
+    }
+
+    /**
      * Register a callback to be invoked when the context menu for this view is
      * being built. If this view is not long clickable, it becomes long clickable.
      *
@@ -4881,6 +4958,46 @@
     }
 
     /**
+     * Call this view's OnStylusButtonPressListener, if it is defined.
+     *
+     * @return True if there was an assigned OnStylusButtonPressListener that consumed the event,
+     *         false otherwise.
+     */
+    public boolean performStylusButtonPress() {
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_STYLUS_BUTTON_PRESSED);
+
+        boolean handled = false;
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnStylusButtonPressListener != null) {
+            handled = li.mOnStylusButtonPressListener.onStylusButtonPress(View.this);
+        }
+        if (handled) {
+            performHapticFeedback(HapticFeedbackConstants.STYLUS_BUTTON_PRESS);
+        }
+        return handled;
+    }
+
+    /**
+     * Checks for a stylus button press and calls the listener.
+     *
+     * @param event The event.
+     * @return True if the event was consumed.
+     */
+    private boolean performStylusActionOnButtonPress(MotionEvent event) {
+        if (isStylusButtonPressable() && !mInStylusButtonPress
+                && !mHasPerformedLongPress && event.isStylusButtonPressed()) {
+            if (performStylusButtonPress()) {
+                mInStylusButtonPress = true;
+                setPressed(true, event.getX(), event.getY());
+                removeTapCallback();
+                removeLongPressCallback();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Performs button-related actions during a touch down event.
      *
      * @param event The event.
@@ -5670,6 +5787,7 @@
      *   <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li>
      *   <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li>
      *   <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li>
+     *   <li>{@link AccessibilityNodeInfo#setStylusButtonPressable(boolean)}</li>
      * </ul>
      * <p>
      * Subclasses should override this method, call the super implementation,
@@ -5821,6 +5939,9 @@
                 structure.setChecked(true);
             }
         }
+        if (isStylusButtonPressable()) {
+            structure.setStylusButtonPressable(true);
+        }
         structure.setClassName(getAccessibilityClassName().toString());
         structure.setContentDescription(getContentDescription());
     }
@@ -5878,6 +5999,9 @@
                 structure.setChecked(true);
             }
         }
+        if (info.isStylusButtonPressable()) {
+            structure.setStylusButtonPressable(true);
+        }
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
@@ -6007,6 +6131,7 @@
         info.setAccessibilityFocused(isAccessibilityFocused());
         info.setSelected(isSelected());
         info.setLongClickable(isLongClickable());
+        info.setStylusButtonPressable(isStylusButtonPressable());
         info.setLiveRegion(getAccessibilityLiveRegion());
 
         // TODO: These make sense only if we are in an AdapterView but all
@@ -6037,6 +6162,10 @@
             info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
         }
 
+        if (isStylusButtonPressable() && isEnabled()) {
+            info.addAction(AccessibilityAction.ACTION_STYLUS_BUTTON_PRESS);
+        }
+
         CharSequence text = getIterableTextForAccessibility();
         if (text != null && text.length() > 0) {
             info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd());
@@ -7411,6 +7540,31 @@
     }
 
     /**
+     * Indicates whether this view reacts to stylus button press events or not.
+     *
+     * @return true if the view is stylus button pressable, false otherwise
+     * @see #setStylusButtonPressable(boolean)
+     * @attr ref android.R.styleable#View_stylusButtonPressable
+     */
+    public boolean isStylusButtonPressable() {
+        return (mViewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE;
+    }
+
+    /**
+     * Enables or disables stylus button press events for this view. When a view is stylus button
+     * pressable it reacts to the user touching the screen with a stylus and pressing the first
+     * stylus button. This event can launch the listener.
+     *
+     * @param stylusButtonPressable true to make the view react to a stylus button press, false
+     *            otherwise
+     * @see #isStylusButtonPressable()
+     * @attr ref android.R.styleable#View_stylusButtonPressable
+     */
+    public void setStylusButtonPressable(boolean stylusButtonPressable) {
+        setFlags(stylusButtonPressable ? STYLUS_BUTTON_PRESSABLE : 0, STYLUS_BUTTON_PRESSABLE);
+    }
+
+    /**
      * Sets the pressed state for this view and provides a touch coordinate for
      * animation hinting.
      *
@@ -7825,7 +7979,8 @@
     public void addTouchables(ArrayList<View> views) {
         final int viewFlags = mViewFlags;
 
-        if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
+        if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE
+                || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE)
                 && (viewFlags & ENABLED_MASK) == ENABLED) {
             views.add(this);
         }
@@ -8540,6 +8695,12 @@
                     return requestRectangleOnScreen(r, true);
                 }
             } break;
+            case R.id.accessibilityActionStylusButtonPress: {
+                if (isStylusButtonPressable()) {
+                    performStylusButtonPress();
+                    return true;
+                }
+            } break;
         }
         return false;
     }
@@ -9697,7 +9858,8 @@
         }
 
         return (viewFlags & CLICKABLE) == CLICKABLE
-                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
+                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE
+                || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE;
     }
 
     /**
@@ -9780,15 +9942,17 @@
         final float x = event.getX();
         final float y = event.getY();
         final int viewFlags = mViewFlags;
+        final int action = event.getAction();
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
-            if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
+            if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
             // events, it just doesn't respond to them.
-            return (((viewFlags & CLICKABLE) == CLICKABLE ||
-                    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
+            return (((viewFlags & CLICKABLE) == CLICKABLE
+                    || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
+                    || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE);
         }
 
         if (mTouchDelegate != null) {
@@ -9798,9 +9962,14 @@
         }
 
         if (((viewFlags & CLICKABLE) == CLICKABLE ||
-                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
-            switch (event.getAction()) {
+                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
+                (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) {
+            switch (action) {
                 case MotionEvent.ACTION_UP:
+                    if (mInStylusButtonPress) {
+                        mInStylusButtonPress = false;
+                        mHasPerformedLongPress = false;
+                    }
                     boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                     if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                         // take focus if we don't have it already and we should in
@@ -9854,6 +10023,11 @@
 
                 case MotionEvent.ACTION_DOWN:
                     mHasPerformedLongPress = false;
+                    mInStylusButtonPress = false;
+
+                    if (performStylusActionOnButtonPress(event)) {
+                        break;
+                    }
 
                     if (performButtonActionOnTouchDown(event)) {
                         break;
@@ -9883,6 +10057,10 @@
                     setPressed(false);
                     removeTapCallback();
                     removeLongPressCallback();
+                    if (mInStylusButtonPress) {
+                        mInStylusButtonPress = false;
+                        mHasPerformedLongPress = false;
+                    }
                     break;
 
                 case MotionEvent.ACTION_MOVE:
@@ -9898,6 +10076,9 @@
 
                             setPressed(false);
                         }
+                    } else if (performStylusActionOnButtonPress(event)) {
+                        // Check for stylus button press if we're within the view.
+                        break;
                     }
                     break;
             }
@@ -10185,7 +10366,8 @@
 
         if (accessibilityEnabled) {
             if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0
-                    || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0) {
+                    || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
+                    || (changed & STYLUS_BUTTON_PRESSABLE) != 0) {
                 if (oldIncludeForAccessibility != includeForAccessibility()) {
                     notifySubtreeAccessibilityStateChangedIfNeeded();
                 } else {
@@ -14342,15 +14524,6 @@
     }
 
     /**
-     * Indicates whether this view has a static layer. A view with layer type
-     * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are
-     * dynamic.
-     */
-    boolean hasStaticLayer() {
-        return true;
-    }
-
-    /**
      * Indicates what type of layer is currently associated with this view. By default
      * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
      * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)}
@@ -15468,12 +15641,8 @@
                         if (drawingWithRenderNode) {
                             renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else if (layerType == LAYER_TYPE_NONE) {
-                            int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-                            if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0) {
-                                layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
-                            }
                             canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
-                                    multipliedAlpha, layerFlags);
+                                    multipliedAlpha);
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
@@ -15509,7 +15678,7 @@
         if (!drawingWithDrawingCache) {
             if (drawingWithRenderNode) {
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                ((DisplayListCanvas) canvas).drawRenderNode(renderNode, parentFlags);
+                ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
             } else {
                 // Fast path for layouts with no backgrounds
                 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -20764,6 +20933,20 @@
     }
 
     /**
+     * Interface definition for a callback to be invoked when a view is touched with a stylus while
+     * the stylus button is pressed.
+     */
+    public interface OnStylusButtonPressListener {
+        /**
+         * Called when a view is touched with a stylus while the stylus button is pressed.
+         *
+         * @param v The view that was touched.
+         * @return true if the callback consumed the stylus button press, false otherwise.
+         */
+        boolean onStylusButtonPress(View v);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when the context menu
      * for this view is being built.
      */
diff --git a/core/java/android/view/ViewAssistStructure.java b/core/java/android/view/ViewAssistStructure.java
index 346b8ec..fccfbb8 100644
--- a/core/java/android/view/ViewAssistStructure.java
+++ b/core/java/android/view/ViewAssistStructure.java
@@ -40,6 +40,8 @@
 
     public abstract void setLongClickable(boolean state);
 
+    public abstract void setStylusButtonPressable(boolean state);
+
     public abstract void setFocusable(boolean state);
 
     public abstract void setFocused(boolean state);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4324e75..d0d4201 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3505,8 +3505,7 @@
         final View[] children = mChildren;
         for (int i = 0; i < count; i++) {
             final View child = children[i];
-            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
-                    child.hasStaticLayer()) {
+            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
                 recreateChildDisplayList(child);
             }
         }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 417e22c..b0dbeca 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -684,6 +684,11 @@
     public static final int TYPE_WINDOWS_CHANGED = 0x00400000;
 
     /**
+     * Represents the event of a stylus button press on a {@link android.view.View}.
+     */
+    public static final int TYPE_VIEW_STYLUS_BUTTON_PRESSED = 0x00800000;
+
+    /**
      * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
      * The type of change is not defined.
      */
@@ -731,6 +736,7 @@
      * @see #TYPE_TOUCH_INTERACTION_START
      * @see #TYPE_TOUCH_INTERACTION_END
      * @see #TYPE_WINDOWS_CHANGED
+     * @see #TYPE_VIEW_STYLUS_BUTTON_PRESSED
      */
     public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
 
@@ -1396,6 +1402,14 @@
                     builder.append("TYPE_WINDOWS_CHANGED");
                     eventTypeCount++;
                 } break;
+                case TYPE_VIEW_STYLUS_BUTTON_PRESSED: {
+                    if (eventTypeCount > 0) {
+                        builder.append(", ");
+                    }
+                    builder.append("TYPE_VIEW_STYLUS_BUTTON_PRESSED");
+                    eventTypeCount++;
+                }
+                    break;
             }
         }
         if (eventTypeCount > 1) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 0736ed8..bf4b7ae 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -520,6 +520,8 @@
 
     private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
 
+    private static final int BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE = 0x00020000;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -1930,6 +1932,30 @@
     }
 
     /**
+     * Gets whether this node is stylus button pressable.
+     *
+     * @return True if the node is stylus button pressable.
+     */
+    public boolean isStylusButtonPressable() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE);
+    }
+
+    /**
+     * Sets whether this node is stylus button pressable.
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an
+     * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
+     * before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param stylusButtonPressable True if the node is stylus button pressable.
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setStylusButtonPressable(boolean stylusButtonPressable) {
+        setBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE, stylusButtonPressable);
+    }
+
+    /**
      * Gets the node's live region mode.
      * <p>
      * A live region is a node that contains information that is important for
@@ -3117,6 +3143,7 @@
         builder.append("; selected: ").append(isSelected());
         builder.append("; clickable: ").append(isClickable());
         builder.append("; longClickable: ").append(isLongClickable());
+        builder.append("; stylusButtonPressable: ").append(isStylusButtonPressable());
         builder.append("; enabled: ").append(isEnabled());
         builder.append("; password: ").append(isPassword());
         builder.append("; scrollable: ").append(isScrollable());
@@ -3472,6 +3499,12 @@
         public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
                 new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
 
+        /**
+         * Action that stylus button presses the node.
+         */
+        public static final AccessibilityAction ACTION_STYLUS_BUTTON_PRESS =
+                new AccessibilityAction(R.id.accessibilityActionStylusButtonPress, null);
+
         private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
         static {
             sStandardActions.add(ACTION_FOCUS);
@@ -3498,6 +3531,7 @@
             sStandardActions.add(ACTION_SET_TEXT);
             sStandardActions.add(ACTION_SHOW_ON_SCREEN);
             sStandardActions.add(ACTION_SCROLL_TO_POSITION);
+            sStandardActions.add(ACTION_STYLUS_BUTTON_PRESS);
         }
 
         private final int mActionId;
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 478fa00..d271af2 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -286,14 +286,10 @@
         return null;
     }
 
-    private boolean isCalendarInRange(Calendar value) {
-        return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
-    }
-
     private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
         @Override
         public void onDayClick(SimpleMonthView view, Calendar day) {
-            if (day != null && isCalendarInRange(day)) {
+            if (day != null) {
                 setSelectedDay(day);
 
                 if (mOnDaySelectedListener != null) {
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 113e597..334afab 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -178,6 +178,13 @@
         });
     }
 
+    private void updateButtonVisibility(int position) {
+        final boolean hasPrev = position > 0;
+        final boolean hasNext = position < (mAdapter.getCount() - 1);
+        mPrevButton.setVisibility(hasPrev ? View.VISIBLE : View.INVISIBLE);
+        mNextButton.setVisibility(hasNext ? View.VISIBLE : View.INVISIBLE);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final ViewPager viewPager = mViewPager;
@@ -218,12 +225,6 @@
         final int height = bottom - top;
         mViewPager.layout(0, 0, width, height);
 
-        if (mViewPager.getChildCount() < 1) {
-            leftButton.setVisibility(View.INVISIBLE);
-            rightButton.setVisibility(View.INVISIBLE);
-            return;
-        }
-
         final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0);
         final int monthHeight = monthView.getMonthHeight();
         final int cellWidth = monthView.getCellWidth();
@@ -235,7 +236,6 @@
         final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2;
         final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2;
         leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH);
-        leftButton.setVisibility(View.VISIBLE);
 
         final int rightDW = rightButton.getMeasuredWidth();
         final int rightDH = rightButton.getMeasuredHeight();
@@ -243,7 +243,6 @@
         final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2;
         rightButton.layout(rightIconRight - rightDW, rightIconTop,
                 rightIconRight, rightIconTop + rightDH);
-        rightButton.setVisibility(View.VISIBLE);
     }
 
     public void setDayOfWeekTextAppearance(int resId) {
@@ -399,10 +398,7 @@
 
         @Override
         public void onPageSelected(int position) {
-            mPrevButton.setVisibility(
-                    position > 0 ? View.VISIBLE : View.INVISIBLE);
-            mNextButton.setVisibility(
-                    position < (mAdapter.getCount() - 1) ? View.VISIBLE : View.INVISIBLE);
+            updateButtonVisibility(position);
         }
     };
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 39b9907..35e7389 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -62,7 +62,6 @@
 import android.text.method.KeyListener;
 import android.text.method.MetaKeyKeyListener;
 import android.text.method.MovementMethod;
-import android.text.method.PasswordTransformationMethod;
 import android.text.method.WordIterator;
 import android.text.style.EasyEditSpan;
 import android.text.style.SuggestionRangeSpan;
@@ -145,16 +144,16 @@
     InputContentType mInputContentType;
     InputMethodState mInputMethodState;
 
-    private static class TextDisplayList {
-        RenderNode displayList;
+    private static class TextRenderNode {
+        RenderNode renderNode;
         boolean isDirty;
-        public TextDisplayList(String name) {
+        public TextRenderNode(String name) {
             isDirty = true;
-            displayList = RenderNode.create(name, null);
+            renderNode = RenderNode.create(name, null);
         }
-        boolean needsRecord() { return isDirty || !displayList.isValid(); }
+        boolean needsRecord() { return isDirty || !renderNode.isValid(); }
     }
-    TextDisplayList[] mTextDisplayLists;
+    TextRenderNode[] mTextRenderNodes;
 
     boolean mFrozenWithFocus;
     boolean mSelectionMoved;
@@ -360,10 +359,10 @@
     }
 
     private void destroyDisplayListsData() {
-        if (mTextDisplayLists != null) {
-            for (int i = 0; i < mTextDisplayLists.length; i++) {
-                RenderNode displayList = mTextDisplayLists[i] != null
-                        ? mTextDisplayLists[i].displayList : null;
+        if (mTextRenderNodes != null) {
+            for (int i = 0; i < mTextRenderNodes.length; i++) {
+                RenderNode displayList = mTextRenderNodes[i] != null
+                        ? mTextRenderNodes[i].renderNode : null;
                 if (displayList != null && displayList.isValid()) {
                     displayList.destroyDisplayListData();
                 }
@@ -682,34 +681,6 @@
         }
     }
 
-    /**
-     * Unlike {@link TextView#textCanBeSelected()}, this method is based on the <i>current</i> state
-     * of the TextView. textCanBeSelected() has to be true (this is one of the conditions to have
-     * a selection controller (see {@link #prepareCursorControllers()}), but this is not sufficient.
-     */
-    private boolean canSelectText() {
-        return hasSelectionController() && mTextView.getText().length() != 0;
-    }
-
-    /**
-     * It would be better to rely on the input type for everything. A password inputType should have
-     * a password transformation. We should hence use isPasswordInputType instead of this method.
-     *
-     * We should:
-     * - Call setInputType in setKeyListener instead of changing the input type directly (which
-     * would install the correct transformation).
-     * - Refuse the installation of a non-password transformation in setTransformation if the input
-     * type is password.
-     *
-     * However, this is like this for legacy reasons and we cannot break existing apps. This method
-     * is useful since it matches what the user can see (obfuscated text or not).
-     *
-     * @return true if the current transformation method is of the password type.
-     */
-    private boolean hasPasswordTransformationMethod() {
-        return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
-    }
-
     private int getWordStart(int offset) {
         // FIXME - For this and similar methods we're not doing anything to check if there's
         // a LocaleSpan in the text, this may be something we should try handling or checking for.
@@ -758,11 +729,11 @@
      * successfully performed.
      */
     private boolean selectCurrentWord() {
-        if (!canSelectText()) {
+        if (!mTextView.canSelectText()) {
             return false;
         }
 
-        if (hasPasswordTransformationMethod()) {
+        if (mTextView.hasPasswordTransformationMethod()) {
             // Always select all on a password field.
             // Cut/copy menu entries are not available for passwords, but being able to select all
             // is however useful to delete or paste to replace the entire content.
@@ -1467,8 +1438,8 @@
                 firstLine, lastLine);
 
         if (layout instanceof DynamicLayout) {
-            if (mTextDisplayLists == null) {
-                mTextDisplayLists = ArrayUtils.emptyArray(TextDisplayList.class);
+            if (mTextRenderNodes == null) {
+                mTextRenderNodes = ArrayUtils.emptyArray(TextRenderNode.class);
             }
 
             DynamicLayout dynamicLayout = (DynamicLayout) layout;
@@ -1489,19 +1460,19 @@
                             searchStartIndex);
                     // Note how dynamic layout's internal block indices get updated from Editor
                     blockIndices[i] = blockIndex;
-                    if (mTextDisplayLists[blockIndex] != null) {
-                        mTextDisplayLists[blockIndex].isDirty = true;
+                    if (mTextRenderNodes[blockIndex] != null) {
+                        mTextRenderNodes[blockIndex].isDirty = true;
                     }
                     searchStartIndex = blockIndex + 1;
                 }
 
-                if (mTextDisplayLists[blockIndex] == null) {
-                    mTextDisplayLists[blockIndex] =
-                            new TextDisplayList("Text " + blockIndex);
+                if (mTextRenderNodes[blockIndex] == null) {
+                    mTextRenderNodes[blockIndex] =
+                            new TextRenderNode("Text " + blockIndex);
                 }
 
-                final boolean blockDisplayListIsInvalid = mTextDisplayLists[blockIndex].needsRecord();
-                RenderNode blockDisplayList = mTextDisplayLists[blockIndex].displayList;
+                final boolean blockDisplayListIsInvalid = mTextRenderNodes[blockIndex].needsRecord();
+                RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode;
                 if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
                     final int blockBeginLine = endOfPreviousBlock + 1;
                     final int top = layout.getLineTop(blockBeginLine);
@@ -1528,7 +1499,7 @@
                             // brings this range of text back to the top left corner of the viewport
                             displayListCanvas.translate(-left, -top);
                             layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
-                            mTextDisplayLists[blockIndex].isDirty = false;
+                            mTextRenderNodes[blockIndex].isDirty = false;
                             // No need to untranslate, previous context is popped after
                             // drawDisplayList
                         } finally {
@@ -1543,8 +1514,7 @@
                     blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
                 }
 
-                ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList,
-                        0 /* no child clipping, our TextView parent enforces it */);
+                ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
 
                 endOfPreviousBlock = blockEndLine;
             }
@@ -1558,7 +1528,7 @@
 
     private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks,
             int searchStartIndex) {
-        int length = mTextDisplayLists.length;
+        int length = mTextRenderNodes.length;
         for (int i = searchStartIndex; i < length; i++) {
             boolean blockIndexFound = false;
             for (int j = 0; j < numberOfBlocks; j++) {
@@ -1572,7 +1542,7 @@
         }
 
         // No available index found, the pool has to grow
-        mTextDisplayLists = GrowingArrayUtils.append(mTextDisplayLists, length, null);
+        mTextRenderNodes = GrowingArrayUtils.append(mTextRenderNodes, length, null);
         return length;
     }
 
@@ -1589,7 +1559,7 @@
      * Invalidates all the sub-display lists that overlap the specified character range
      */
     void invalidateTextDisplayList(Layout layout, int start, int end) {
-        if (mTextDisplayLists != null && layout instanceof DynamicLayout) {
+        if (mTextRenderNodes != null && layout instanceof DynamicLayout) {
             final int firstLine = layout.getLineForOffset(start);
             final int lastLine = layout.getLineForOffset(end);
 
@@ -1609,7 +1579,7 @@
             while (i < numberOfBlocks) {
                 final int blockIndex = blockIndices[i];
                 if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
-                    mTextDisplayLists[blockIndex].isDirty = true;
+                    mTextRenderNodes[blockIndex].isDirty = true;
                 }
                 if (blockEndLines[i] >= lastLine) break;
                 i++;
@@ -1618,9 +1588,9 @@
     }
 
     void invalidateTextDisplayList() {
-        if (mTextDisplayLists != null) {
-            for (int i = 0; i < mTextDisplayLists.length; i++) {
-                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].isDirty = true;
+        if (mTextRenderNodes != null) {
+            for (int i = 0; i < mTextRenderNodes.length; i++) {
+                if (mTextRenderNodes[i] != null) mTextRenderNodes[i].isDirty = true;
             }
         }
     }
@@ -1718,7 +1688,7 @@
             return false;
         }
 
-        if (!canSelectText() || !mTextView.requestFocus()) {
+        if (!mTextView.canSelectText() || !mTextView.requestFocus()) {
             Log.w(TextView.LOG_TAG,
                     "TextView does not support text selection. Action mode cancelled.");
             return false;
@@ -3090,7 +3060,7 @@
                                 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
             }
 
-            if (canSelectText() && !hasPasswordTransformationMethod()) {
+            if (mTextView.canSelectAllText()) {
                 menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
                         setAlphabeticShortcut('a').
                         setShowAsAction(
@@ -3847,6 +3817,10 @@
                                 startSelectionActionModeWithoutSelection();
                             }
                         }
+                    } else {
+                        if (mSelectionActionMode != null) {
+                            mSelectionActionMode.invalidateContentRect();
+                        }
                     }
                     hideAfterDelay();
                     break;
@@ -4491,7 +4465,7 @@
 
     private class CorrectionHighlighter {
         private final Path mPath = new Path();
-        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        private final Paint mPaint = new Paint();
         private int mStart, mEnd;
         private long mFadingStartTime;
         private RectF mTempRectF;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index bbf120a..088adbb 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -18,6 +18,7 @@
 
 import static android.widget.SuggestionsAdapter.getColumnString;
 
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -120,6 +121,8 @@
     private final Intent mVoiceWebSearchIntent;
     private final Intent mVoiceAppSearchIntent;
 
+    private final CharSequence mDefaultQueryHint;
+
     private OnQueryTextListener mOnQueryChangeListener;
     private OnCloseListener mOnCloseListener;
     private OnFocusChangeListener mOnQueryTextFocusChangeListener;
@@ -329,10 +332,8 @@
             setMaxWidth(maxWidth);
         }
 
-        final CharSequence queryHint = a.getText(R.styleable.SearchView_queryHint);
-        if (!TextUtils.isEmpty(queryHint)) {
-            setQueryHint(queryHint);
-        }
+        mDefaultQueryHint = a.getText(R.styleable.SearchView_defaultQueryHint);
+        mQueryHint = a.getText(R.styleable.SearchView_queryHint);
 
         final int imeOptions = a.getInt(R.styleable.SearchView_imeOptions, -1);
         if (imeOptions != -1) {
@@ -570,36 +571,48 @@
     }
 
     /**
-     * Sets the hint text to display in the query text field. This overrides any hint specified
-     * in the SearchableInfo.
+     * Sets the hint text to display in the query text field. This overrides
+     * any hint specified in the {@link SearchableInfo}.
+     * <p>
+     * This value may be specified as an empty string to prevent any query hint
+     * from being displayed.
      *
-     * @param hint the hint text to display
-     *
+     * @param hint the hint text to display or {@code null} to clear
      * @attr ref android.R.styleable#SearchView_queryHint
      */
-    public void setQueryHint(CharSequence hint) {
+    public void setQueryHint(@Nullable CharSequence hint) {
         mQueryHint = hint;
         updateQueryHint();
     }
 
     /**
-     * Gets the hint text to display in the query text field.
-     * @return the query hint text, if specified, null otherwise.
+     * Returns the hint text that will be displayed in the query text field.
+     * <p>
+     * The displayed query hint is chosen in the following order:
+     * <ol>
+     * <li>Non-null value set with {@link #setQueryHint(CharSequence)}
+     * <li>Value specified in XML using
+     *     {@link android.R.styleable#SearchView_queryHint android:queryHint}
+     * <li>Valid string resource ID exposed by the {@link SearchableInfo} via
+     *     {@link SearchableInfo#getHintId()}
+     * <li>Default hint provided by the theme against which the view was
+     *     inflated
+     * </ol>
      *
+     * @return the displayed query hint text, or {@code null} if none set
      * @attr ref android.R.styleable#SearchView_queryHint
      */
+    @Nullable
     public CharSequence getQueryHint() {
+        final CharSequence hint;
         if (mQueryHint != null) {
-            return mQueryHint;
-        } else if (mSearchable != null) {
-            CharSequence hint = null;
-            int hintId = mSearchable.getHintId();
-            if (hintId != 0) {
-                hint = getContext().getString(hintId);
-            }
-            return hint;
+            hint = mQueryHint;
+        } else if (mSearchable != null && mSearchable.getHintId() != 0) {
+            hint = getContext().getText(mSearchable.getHintId());
+        } else {
+            hint = mDefaultQueryHint;
         }
-        return null;
+        return hint;
     }
 
     /**
@@ -1113,20 +1126,8 @@
     }
 
     private void updateQueryHint() {
-        if (mQueryHint != null) {
-            mSearchSrcTextView.setHint(getDecoratedHint(mQueryHint));
-        } else if (mSearchable != null) {
-            CharSequence hint = null;
-            int hintId = mSearchable.getHintId();
-            if (hintId != 0) {
-                hint = getContext().getString(hintId);
-            }
-            if (hint != null) {
-                mSearchSrcTextView.setHint(getDecoratedHint(hint));
-            }
-        } else {
-            mSearchSrcTextView.setHint(getDecoratedHint(""));
-        }
+        final CharSequence hint = getQueryHint();
+        mSearchSrcTextView.setHint(getDecoratedHint(hint == null ? "" : hint));
     }
 
     /**
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 2778f0f..acf1df9 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -31,6 +31,7 @@
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.IntArray;
+import android.util.MathUtils;
 import android.util.StateSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -422,7 +423,8 @@
 
             int stateMask = 0;
 
-            if (day >= mEnabledDayStart && day <= mEnabledDayEnd) {
+            final boolean isDayEnabled = isDayEnabled(day);
+            if (isDayEnabled) {
                 stateMask |= StateSet.VIEW_STATE_ENABLED;
             }
 
@@ -435,8 +437,11 @@
             } else if (mTouchedItem == day) {
                 stateMask |= StateSet.VIEW_STATE_PRESSED;
 
-                // Adjust the circle to be centered on the row.
-                canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDayHighlightPaint);
+                if (isDayEnabled) {
+                    // Adjust the circle to be centered on the row.
+                    canvas.drawCircle(colCenterRtl, rowCenter,
+                            mDaySelectorRadius, mDayHighlightPaint);
+                }
             }
 
             final boolean isDayToday = mToday == day;
@@ -460,6 +465,14 @@
         }
     }
 
+    private boolean isDayEnabled(int day) {
+        return day >= mEnabledDayStart && day <= mEnabledDayEnd;
+    }
+
+    private boolean isValidDayOfMonth(int day) {
+        return day >= 1 && day <= mDaysInMonth;
+    }
+
     private static boolean isValidDayOfWeek(int day) {
         return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY;
     }
@@ -536,13 +549,6 @@
             mWeekStart = mCalendar.getFirstDayOfWeek();
         }
 
-        if (enabledDayStart > 0 && enabledDayEnd < 32) {
-            mEnabledDayStart = enabledDayStart;
-        }
-        if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) {
-            mEnabledDayEnd = enabledDayEnd;
-        }
-
         // Figure out what day today is.
         final Calendar today = Calendar.getInstance();
         mToday = -1;
@@ -554,6 +560,9 @@
             }
         }
 
+        mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
+        mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
+
         // Invalidate the old title.
         mTitle = null;
 
@@ -694,7 +703,7 @@
         final int col = (paddedXRtl * DAYS_IN_WEEK) / mPaddedWidth;
         final int index = col + row * DAYS_IN_WEEK;
         final int day = index + 1 - findDayOffset();
-        if (day < 1 || day > mDaysInMonth) {
+        if (!isValidDayOfMonth(day)) {
             return -1;
         }
 
@@ -708,7 +717,7 @@
      * @param outBounds the rect to populate with bounds
      */
     private boolean getBoundsForDay(int id, Rect outBounds) {
-        if (id < 1 || id > mDaysInMonth) {
+        if (!isValidDayOfMonth(id)) {
             return false;
         }
 
@@ -742,7 +751,7 @@
      * @param day the day that was clicked
      */
     private boolean onDayClicked(int day) {
-        if (day < 0 || day > mDaysInMonth) {
+        if (!isValidDayOfMonth(day) || !isDayEnabled(day)) {
             return false;
         }
 
@@ -774,7 +783,7 @@
         @Override
         protected int getVirtualViewAt(float x, float y) {
             final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
-            if (day >= 0) {
+            if (day != -1) {
                 return day;
             }
             return ExploreByTouchHelper.INVALID_ID;
@@ -808,7 +817,13 @@
             node.setText(getDayText(virtualViewId));
             node.setContentDescription(getDayDescription(virtualViewId));
             node.setBoundsInParent(mTempRect);
-            node.addAction(AccessibilityAction.ACTION_CLICK);
+
+            final boolean isDayEnabled = isDayEnabled(virtualViewId);
+            if (isDayEnabled) {
+                node.addAction(AccessibilityAction.ACTION_CLICK);
+            }
+
+            node.setEnabled(isDayEnabled);
 
             if (virtualViewId == mActivatedDay) {
                 // TODO: This should use activated once that's supported.
@@ -835,7 +850,7 @@
          * @return a description of the virtual view
          */
         private CharSequence getDayDescription(int id) {
-            if (id >= 1 && id <= mDaysInMonth) {
+            if (isValidDayOfMonth(id)) {
                 mTempCalendar.set(mYear, mMonth, id);
                 return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis());
             }
@@ -850,7 +865,7 @@
          * @return the visible text of the virtual view
          */
         private CharSequence getDayText(int id) {
-            if (id >= 1 && id <= mDaysInMonth) {
+            if (isValidDayOfMonth(id)) {
                 return Integer.toString(id);
             }
 
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index ae779fe..f94f97c 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -216,7 +216,7 @@
     public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
-        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint = new TextPaint();
 
         final Resources res = getResources();
         mTextPaint.density = res.getDisplayMetrics().density;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3e8df08..774a864 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -668,11 +668,11 @@
         final Resources res = getResources();
         final CompatibilityInfo compat = res.getCompatibilityInfo();
 
-        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint = new TextPaint();
         mTextPaint.density = res.getDisplayMetrics().density;
         mTextPaint.setCompatibilityScaling(compat.applicationScale);
 
-        mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mHighlightPaint = new Paint();
         mHighlightPaint.setCompatibilityScaling(compat.applicationScale);
 
         mMovement = getDefaultMovementMethod();
@@ -4569,7 +4569,7 @@
      *
      * @return true if the current transformation method is of the password type.
      */
-    private boolean hasPasswordTransformationMethod() {
+    boolean hasPasswordTransformationMethod() {
         return mTransformation instanceof PasswordTransformationMethod;
     }
 
@@ -8583,7 +8583,7 @@
      * a selection controller (see {@link Editor#prepareCursorControllers()}), but this is not
      * sufficient.
      */
-    private boolean canSelectText() {
+    boolean canSelectText() {
         return mText.length() != 0 && mEditor != null && mEditor.hasSelectionController();
     }
 
@@ -9199,6 +9199,10 @@
         return false;
     }
 
+    boolean canSelectAllText() {
+        return canSelectText() && !hasPasswordTransformationMethod();
+    }
+
     boolean selectAllText() {
         // Need to hide insert point cursor controller before settings selection, otherwise insert
         // point cursor controller obtains cursor update event and update cursor with cancelling
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2b77b2c..e347faa 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -405,8 +405,10 @@
                 int launchedFromUid, boolean filterLastUsed, ChooserTarget[] callerChooserTargets) {
             super(context, initialIntents, rList, launchedFromUid, filterLastUsed);
 
-            for (ChooserTarget target : callerChooserTargets) {
-                mCallerTargets.add(new ChooserTargetInfo(target));
+            if (callerChooserTargets != null) {
+                for (ChooserTarget target : callerChooserTargets) {
+                    mCallerTargets.add(new ChooserTargetInfo(target));
+                }
             }
         }
 
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index eff44bd..481ab0e 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -44,7 +44,6 @@
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
         sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
-        sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
         sPackageFilt.addDataScheme("package");
         sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
         sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 092c148..3f96174 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,11 +26,12 @@
  */
 public class MetricsLogger implements MetricsConstants {
     // These constants are temporary, they should migrate to MetricsConstants.
-    // next value is 146;
+    // next value is 148;
 
     public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
     public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
     public static final int ACTION_BAN_APP_NOTES = 146;
+    public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 147;
 
     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/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java
index 53d71bb..8ed5b5a 100644
--- a/core/java/com/android/internal/midi/MidiFramer.java
+++ b/core/java/com/android/internal/midi/MidiFramer.java
@@ -17,6 +17,7 @@
 package com.android.internal.midi;
 
 import android.media.midi.MidiReceiver;
+import android.util.Log;
 
 import java.io.IOException;
 
@@ -38,6 +39,7 @@
     private int mCount;
     private int mRunningStatus;
     private int mNeeded;
+    private boolean mInSysEx;
 
     public MidiFramer(MidiReceiver receiver) {
         mReceiver = receiver;
@@ -52,12 +54,14 @@
     }
 
     /*
-     * @see android.midi.MidiReceiver#onPost(byte[], int, int, long)
+     * @see android.midi.MidiReceiver#onReceive(byte[], int, int, long)
      */
     @Override
     public void onReceive(byte[] data, int offset, int count, long timestamp)
             throws IOException {
         // Log.i(TAG, formatMidiData(data, offset, count));
+        int sysExStartOffset = (mInSysEx ? offset : -1);
+
         for (int i = 0; i < count; i++) {
             int b = data[offset] & 0xFF;
             if (b >= 0x80) { // status byte?
@@ -66,27 +70,55 @@
                     mCount = 1;
                     mNeeded = MidiConstants.getBytesPerMessage(b) - 1;
                 } else if (b < 0xF8) { // system common?
-                    mBuffer[0] = (byte) b;
-                    mRunningStatus = 0;
-                    mCount = 1;
-                    mNeeded = MidiConstants.getBytesPerMessage(b) - 1;
+                    if (b == 0xF0 /* SysEx Start */) {
+                        // Log.i(TAG, "SysEx Start");
+                        mInSysEx = true;
+                        sysExStartOffset = offset;
+                    } else if (b == 0xF7 /* SysEx End */) {
+                        // Log.i(TAG, "SysEx End");
+                        if (mInSysEx) {
+                            mReceiver.sendWithTimestamp(data, sysExStartOffset,
+                                offset - sysExStartOffset + 1, timestamp);
+                            mInSysEx = false;
+                            sysExStartOffset = -1;
+                        }
+                    } else {
+                        mBuffer[0] = (byte) b;
+                        mRunningStatus = 0;
+                        mCount = 1;
+                        mNeeded = MidiConstants.getBytesPerMessage(b) - 1;
+                    }
                 } else { // real-time?
                     // Single byte message interleaved with other data.
+                    if (mInSysEx) {
+                        mReceiver.sendWithTimestamp(data, sysExStartOffset,
+                                offset - sysExStartOffset, timestamp);
+                        sysExStartOffset = offset + 1;
+                    }
                     mReceiver.sendWithTimestamp(data, offset, 1, timestamp);
                 }
             } else { // data byte
-                mBuffer[mCount++] = (byte) b;
-                if (--mNeeded == 0) {
-                    if (mRunningStatus != 0) {
-                        mBuffer[0] = (byte) mRunningStatus;
+                // Save SysEx data for SysEx End marker or end of buffer.
+                if (!mInSysEx) {
+                    mBuffer[mCount++] = (byte) b;
+                    if (--mNeeded == 0) {
+                        if (mRunningStatus != 0) {
+                            mBuffer[0] = (byte) mRunningStatus;
+                        }
+                        mReceiver.sendWithTimestamp(mBuffer, 0, mCount, timestamp);
+                        mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1;
+                        mCount = 1;
                     }
-                    mReceiver.sendWithTimestamp(mBuffer, 0, mCount, timestamp);
-                    mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1;
-                    mCount = 1;
                 }
             }
             ++offset;
         }
+
+        // send any accumulatedSysEx data
+        if (sysExStartOffset >= 0 && sysExStartOffset < offset) {
+            mReceiver.sendWithTimestamp(data, sysExStartOffset,
+                    offset - sysExStartOffset, timestamp);
+        }
     }
 
 }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 75b6446..1e7ee5a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -40,6 +40,8 @@
     public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
     /** enable the JIT compiler */
     public static final int DEBUG_ENABLE_JIT         = 1 << 5;
+    /** Force generation of CFI code */
+    public static final int DEBUG_GENERATE_CFI       = 1 << 6;
 
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = 0;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 9106ccd..969d236 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -321,7 +321,7 @@
 
         /**
          * From --enable-debugger, --enable-checkjni, --enable-assert,
-         * --enable-safemode, --enable-jit, and --enable-jni-logging.
+         * --enable-safemode, --enable-jit, --generate-cfi and --enable-jni-logging.
          */
         int debugFlags;
 
@@ -433,6 +433,8 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
                 } else if (arg.equals("--enable-jit")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_JIT;
+                } else if (arg.equals("--generate-cfi")) {
+                    debugFlags |= Zygote.DEBUG_GENERATE_CFI;
                 } else if (arg.equals("--enable-jni-logging")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
                 } else if (arg.equals("--enable-assert")) {
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index 7d56e9e..a0d0b20 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -66,7 +66,7 @@
                         COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888
                 );
                 mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap);
-                mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                mTempCompactBitmapPaint = new Paint();
                 mTempCompactBitmapPaint.setFilterBitmap(true);
             }
             mTempMatrix.reset();
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 3a1e0ca..3f7696f 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -438,6 +438,9 @@
             // Make sure a panel is set as the content.
             if (mContentContainer.getChildCount() == 0) {
                 setMainPanelAsContent();
+                // If we're yet to show the popup, set the container visibility to zero.
+                // The "show" animation will make this visible.
+                mContentContainer.setAlpha(0);
             }
             preparePopupContent();
             mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
@@ -478,7 +481,7 @@
          * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
          */
         public boolean isShowing() {
-            return mPopupWindow.isShowing() && !mDismissed && !mHidden;
+            return !mDismissed && !mHidden;
         }
 
         /**
@@ -494,7 +497,7 @@
          * This is a no-op if this popup is not showing.
          */
         public void updateCoordinates(int x, int y) {
-            if (!isShowing()) {
+            if (!isShowing() || !mPopupWindow.isShowing()) {
                 return;
             }
 
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1096e34..3d23986 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,9 +17,11 @@
 package com.android.internal.widget;
 
 import android.Manifest;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
+import android.bluetooth.BluetoothClass;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -142,11 +144,6 @@
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
 
-    private final boolean mMultiUserMode;
-
-    // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
-    private static volatile int sCurrentUserId = UserHandle.USER_NULL;
-
     public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
             mDevicePolicyManager =
@@ -171,12 +168,6 @@
     public LockPatternUtils(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
-
-        // If this is being called by the system or by an application like keyguard that
-        // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user
-        // mode where calls are for the current user rather than the user of the calling process.
-        mMultiUserMode = context.checkCallingOrSelfPermission(
-            Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED;
     }
 
     private ILockSettings getLockSettings() {
@@ -188,93 +179,55 @@
         return mLockSettingsService;
     }
 
-    public int getRequestedMinimumPasswordLength() {
-        return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
+    public int getRequestedMinimumPasswordLength(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
     }
 
     /**
      * Gets the device policy password mode. If the mode is non-specific, returns
      * MODE_PATTERN which allows the user to choose anything.
      */
-    public int getRequestedPasswordQuality() {
-        return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
-    }
-
-    public int getRequestedPasswordHistoryLength() {
-        return getRequestedPasswordHistoryLength(getCurrentOrCallingUserId());
+    public int getRequestedPasswordQuality(int userId) {
+        return getDevicePolicyManager().getPasswordQuality(null, userId);
     }
 
     private int getRequestedPasswordHistoryLength(int userId) {
         return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
     }
 
-    public int getRequestedPasswordMinimumLetters() {
-        return getDevicePolicyManager().getPasswordMinimumLetters(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumLetters(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
     }
 
-    public int getRequestedPasswordMinimumUpperCase() {
-        return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumUpperCase(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
     }
 
-    public int getRequestedPasswordMinimumLowerCase() {
-        return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumLowerCase(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
     }
 
-    public int getRequestedPasswordMinimumNumeric() {
-        return getDevicePolicyManager().getPasswordMinimumNumeric(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumNumeric(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
     }
 
-    public int getRequestedPasswordMinimumSymbols() {
-        return getDevicePolicyManager().getPasswordMinimumSymbols(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumSymbols(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
     }
 
-    public int getRequestedPasswordMinimumNonLetter() {
-        return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
-                getCurrentOrCallingUserId());
+    public int getRequestedPasswordMinimumNonLetter(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
     }
 
-    public void reportFailedPasswordAttempt() {
-        int userId = getCurrentOrCallingUserId();
+    public void reportFailedPasswordAttempt(int userId) {
         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
         getTrustManager().reportRequireCredentialEntry(userId);
     }
 
-    public void reportSuccessfulPasswordAttempt() {
-        getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
-        getTrustManager().reportUnlockAttempt(true /* authenticated */,
-                getCurrentOrCallingUserId());
-    }
-
-    public void setCurrentUser(int userId) {
-        sCurrentUserId = userId;
-    }
-
-    public int getCurrentUser() {
-        if (sCurrentUserId != UserHandle.USER_NULL) {
-            // Someone is regularly updating using setCurrentUser() use that value.
-            return sCurrentUserId;
-        }
-        try {
-            return ActivityManagerNative.getDefault().getCurrentUser().id;
-        } catch (RemoteException re) {
-            return UserHandle.USER_OWNER;
-        }
-    }
-
-    private int getCurrentOrCallingUserId() {
-        if (mMultiUserMode) {
-            // TODO: This is a little inefficient. See if all users of this are able to
-            // handle USER_CURRENT and pass that instead.
-            return getCurrentUser();
-        } else {
-            return UserHandle.getCallingUserId();
-        }
+    public void reportSuccessfulPasswordAttempt(int userId) {
+        getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
+        getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
     }
 
     /**
@@ -286,8 +239,7 @@
      * @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();
+    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) {
         try {
             return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
         } catch (RemoteException re) {
@@ -301,8 +253,7 @@
      * @param pattern The pattern to check.
      * @return Whether the pattern matches the stored one.
      */
-    public boolean checkPattern(List<LockPatternView.Cell> pattern) {
-        final int userId = getCurrentOrCallingUserId();
+    public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) {
         try {
             return getLockSettings().checkPattern(patternToString(pattern), userId);
         } catch (RemoteException re) {
@@ -319,8 +270,7 @@
      * @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();
+    public byte[] verifyPassword(String password, long challenge, int userId) {
         try {
             return getLockSettings().verifyPassword(password, challenge, userId);
         } catch (RemoteException re) {
@@ -334,8 +284,7 @@
      * @param password The password to check.
      * @return Whether the password matches the stored one.
      */
-    public boolean checkPassword(String password) {
-        final int userId = getCurrentOrCallingUserId();
+    public boolean checkPassword(String password, int userId) {
         try {
             return getLockSettings().checkPassword(password, userId);
         } catch (RemoteException re) {
@@ -348,8 +297,7 @@
      * Note that this also clears vold's copy of the password.
      * @return Whether the vold password matches or not.
      */
-    public boolean checkVoldPassword() {
-        final int userId = getCurrentOrCallingUserId();
+    public boolean checkVoldPassword(int userId) {
         try {
             return getLockSettings().checkVoldPassword(userId);
         } catch (RemoteException re) {
@@ -364,8 +312,7 @@
      * @param password The password to check.
      * @return Whether the password matches any in the history.
      */
-    public boolean checkPasswordHistory(String password) {
-        int userId = getCurrentOrCallingUserId();
+    public boolean checkPasswordHistory(String password, int userId) {
         String passwordHashString = new String(
                 passwordToHash(password, userId), StandardCharsets.UTF_8);
         String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
@@ -374,7 +321,7 @@
         }
         // Password History may be too long...
         int passwordHashLength = passwordHashString.length();
-        int passwordHistoryLength = getRequestedPasswordHistoryLength();
+        int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
         if(passwordHistoryLength == 0) {
             return false;
         }
@@ -416,16 +363,8 @@
      *
      * @return True if the user has ever chosen a pattern.
      */
-    public boolean isPatternEverChosen() {
-        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Used by device policy manager to validate the current password
-     * information it has.
-     */
-    public int getActivePasswordQuality() {
-        return getActivePasswordQuality(getCurrentOrCallingUserId());
+    public boolean isPatternEverChosen(int userId) {
+        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
     }
 
     /**
@@ -448,10 +387,6 @@
         return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     }
 
-    public void clearLock() {
-        clearLock(getCurrentOrCallingUserId());
-    }
-
     /**
      * Clear any lock pattern or password.
      */
@@ -479,16 +414,6 @@
     }
 
     /**
-     * Disable showing lock screen at all when the DevicePolicyManager allows it.
-     * This is only meaningful if pattern, pin or password are not set.
-     *
-     * @param disable Disables lock screen when true
-     */
-    public void setLockScreenDisabled(boolean disable) {
-        setLockScreenDisabled(disable, getCurrentOrCallingUserId());
-    }
-
-    /**
      * Disable showing lock screen at all for a given user.
      * This is only meaningful if pattern, pin or password are not set.
      *
@@ -505,21 +430,16 @@
      *
      * @return true if lock screen is disabled
      */
-    public boolean isLockScreenDisabled() {
-        return !isSecure() &&
-                getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId());
+    public boolean isLockScreenDisabled(int userId) {
+        return !isSecure(userId) &&
+                getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId);
     }
 
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
-     * @param savedPattern The previously saved pattern, or null if none
+     * @param userId the user whose pattern is to be saved.
      */
-    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);
     }
@@ -588,8 +508,7 @@
         updateCryptoUserInfo(userId);
     }
 
-    public void setOwnerInfoEnabled(boolean enabled) {
-        int userId = getCurrentOrCallingUserId();
+    public void setOwnerInfoEnabled(boolean enabled, int userId) {
         setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
         updateCryptoUserInfo(userId);
     }
@@ -598,11 +517,7 @@
         return getString(LOCK_SCREEN_OWNER_INFO, userId);
     }
 
-    public boolean isOwnerInfoEnabled() {
-        return isOwnerInfoEnabled(getCurrentOrCallingUserId());
-    }
-
-    private boolean isOwnerInfoEnabled(int userId) {
+    public boolean isOwnerInfoEnabled(int userId) {
         return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
     }
 
@@ -724,21 +639,10 @@
     /**
      * Save a lock password.  Does not ensure that the password is as good
      * as the requested mode, but will adjust the mode to be as good as the
-     * pattern.
+     * password.
      * @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, String savedPassword, int quality) {
-        saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Save a lock password.  Does not ensure that the password is as good
-     * as the requested mode, but will adjust the mode to be as good as the
-     * pattern.
-     * @param password The password to save
-     * @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, String savedPassword, int quality,
@@ -865,16 +769,6 @@
     }
 
     /**
-     * Retrieves the quality mode we're in.
-     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
-     *
-     * @return stored password quality
-     */
-    public int getKeyguardStoredPasswordQuality() {
-        return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
-    }
-
-    /**
      * Retrieves the quality mode for {@param userHandle}.
      * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      *
@@ -997,13 +891,6 @@
     }
 
     /**
-     * @return Whether the lock screen is secured.
-     */
-    public boolean isSecure() {
-        return isSecure(getCurrentOrCallingUserId());
-    }
-
-    /**
      * @param userId the user for which to report the value
      * @return Whether the lock screen is secured.
      */
@@ -1012,13 +899,6 @@
         return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
     }
 
-    /**
-     * @return Whether the lock password is enabled
-     */
-    public boolean isLockPasswordEnabled() {
-        return isLockPasswordEnabled(getCurrentOrCallingUserId());
-    }
-
     public boolean isLockPasswordEnabled(int userId) {
         return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
     }
@@ -1035,10 +915,6 @@
     /**
      * @return Whether the lock pattern is enabled
      */
-    public boolean isLockPatternEnabled() {
-        return isLockPatternEnabled(getCurrentOrCallingUserId());
-    }
-
     public boolean isLockPatternEnabled(int userId) {
         return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
     }
@@ -1051,16 +927,14 @@
     /**
      * @return Whether the visible pattern is enabled.
      */
-    public boolean isVisiblePatternEnabled() {
-        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, getCurrentOrCallingUserId());
+    public boolean isVisiblePatternEnabled(int userId) {
+        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
     }
 
     /**
      * Set whether the visible pattern is enabled.
      */
-    public void setVisiblePatternEnabled(boolean enabled) {
-        int userId = getCurrentOrCallingUserId();
-
+    public void setVisiblePatternEnabled(boolean enabled, int userId) {
         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
 
         // Update for crypto if owner
@@ -1095,9 +969,9 @@
      * pattern until the deadline has passed.
      * @return the chosen deadline.
      */
-    public long setLockoutAttemptDeadline() {
+    public long setLockoutAttemptDeadline(int userId) {
         final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
-        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, getCurrentOrCallingUserId());
+        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
         return deadline;
     }
 
@@ -1106,8 +980,8 @@
      *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
      *   enter a pattern.
      */
-    public long getLockoutAttemptDeadline() {
-        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, getCurrentOrCallingUserId());
+    public long getLockoutAttemptDeadline(int userId) {
+        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
         final long now = SystemClock.elapsedRealtime();
         if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
             return 0L;
@@ -1166,21 +1040,12 @@
         }
     }
 
-    public void setPowerButtonInstantlyLocks(boolean enabled) {
-        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId());
+    public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
+        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
     }
 
-    public boolean getPowerButtonInstantlyLocks() {
-        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true,
-                getCurrentOrCallingUserId());
-    }
-
-    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
-        setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
-    }
-
-    public List<ComponentName> getEnabledTrustAgents() {
-        return getEnabledTrustAgents(getCurrentOrCallingUserId());
+    public boolean getPowerButtonInstantlyLocks(int userId) {
+        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
     }
 
     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
@@ -1192,7 +1057,7 @@
             sb.append(cn.flattenToShortString());
         }
         setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
-        getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
+        getTrustManager().reportEnabledTrustAgentsChanged(userId);
     }
 
     public List<ComponentName> getEnabledTrustAgents(int userId) {
@@ -1228,7 +1093,7 @@
     }
 
     public void setCredentialRequiredToDecrypt(boolean required) {
-        if (getCurrentUser() != UserHandle.USER_OWNER) {
+        if (ActivityManager.getCurrentUser() != UserHandle.USER_OWNER) {
             Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
             return;
         }
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 191662c..6d4e058 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -216,6 +216,8 @@
         if (mVelocityTracker == null) {
             return super.onTouchEvent(ev);
         }
+        // offset because the view is translated during swipe
+        ev.offsetLocation(mTranslationX, 0);
         switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_UP:
                 updateDismiss(ev);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index cd117eb1..bbdd860 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -176,6 +176,7 @@
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
     $(TOP)/frameworks/av/include \
+    $(TOP)/frameworks/base/media/jni \
     $(TOP)/system/media/camera/include \
     $(TOP)/system/netd/include \
     external/pdfium/core/include/fpdfapi \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 88f0697..7c2b28d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -875,6 +875,19 @@
     parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
                        "-Xzygote-max-boot-retry=");
 
+    /*
+     * When running with debug.gencfi, add --include-cfi to the compiler options so that the boot
+     * image, if it is compiled on device, will include CFI info, as well as other compilations
+     * started by the runtime.
+     */
+    property_get("debug.gencfi", propBuf, "");
+    if (strcmp(propBuf, "true") == 0) {
+        addOption("-Xcompiler-option");
+        addOption("--include-cfi");
+        addOption("-Ximage-compiler-option");
+        addOption("--include-cfi");
+    }
+
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
     initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 4c4a39d..d4069a1 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -261,7 +261,7 @@
     SkBitmap* outputBitmap = NULL;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
-        outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap);
+        outputBitmap = GraphicsJNI::getSkBitmapDeprecated(env, javaBitmap);
         if (outputBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
             javaBitmap = NULL;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 3525d07..aeea808 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -217,7 +217,7 @@
 
     if (tileBitmap != NULL) {
         // Re-use bitmap.
-        bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap);
+        bitmap = GraphicsJNI::getSkBitmapDeprecated(env, tileBitmap);
     }
     if (bitmap == NULL) {
         bitmap = new SkBitmap;
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 44037dd..f793df1 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -338,7 +338,7 @@
     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
 }
 
-SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) {
+SkBitmap* GraphicsJNI::getSkBitmapDeprecated(JNIEnv* env, jobject bitmap) {
     SkASSERT(env);
     SkASSERT(bitmap);
     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
@@ -348,6 +348,19 @@
     return b;
 }
 
+void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
+    // TODO: We have to copy from the existing bitmap due to rowBytes not
+    // being updated on the SkPixelRef at reconfigure time. This is a short term
+    // problem that will be fixed with the specialized wrapper
+    *outBitmap = *getSkBitmapDeprecated(env, bitmap);
+}
+
+SkPixelRef* GraphicsJNI::getSkPixelRef(JNIEnv* env, jobject bitmap) {
+    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr);
+    SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return b->pixelRef();
+}
+
 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
     SkASSERT(env);
     if (NULL == jconfig) {
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index d73507e..8eb43f8 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -49,7 +49,9 @@
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
     static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
-    static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap);
+    static SkBitmap* getSkBitmapDeprecated(JNIEnv*, jobject bitmap);
+    static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
+    static SkPixelRef* getSkPixelRef(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 6591d29..d0f7591 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -80,11 +80,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
+static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
                                       jint tileModeX, jint tileModeY)
 {
-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    SkShader* s = SkShader::CreateBitmapShader(bitmap,
                                         (SkShader::TileMode)tileModeX,
                                         (SkShader::TileMode)tileModeY);
 
@@ -249,7 +250,7 @@
 };
 
 static JNINativeMethod gBitmapShaderMethods[] = {
-    { "nativeCreate",     "(JII)J",  (void*)BitmapShader_constructor },
+    { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
 };
 
 static JNINativeMethod gLinearGradientMethods[] = {
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index fc98cf9..876bea4 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -243,19 +243,21 @@
 }
 
 static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
-        jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
+        jobject jbitmap, jint destLeft, jint destTop, jint destRight, jint destBottom,
         jlong matrixPtr, jint renderMode) {
 
     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
-    SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
     SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
 
-    skBitmap->lockPixels();
+    SkBitmap skBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap);
 
-    const int stride = skBitmap->width() * 4;
+    SkAutoLockPixels alp(skBitmap);
 
-    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(),
-            FPDFBitmap_BGRA, skBitmap->getPixels(), stride);
+    const int stride = skBitmap.width() * 4;
+
+    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
+            FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
 
     if (!bitmap) {
         ALOGE("Erorr creating bitmap");
@@ -278,8 +280,7 @@
     renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
             destBottom, skMatrix, renderFlags);
 
-    skBitmap->notifyPixelsChanged();
-    skBitmap->unlockPixels();
+    skBitmap.notifyPixelsChanged();
 }
 
 static JNINativeMethod gPdfRenderer_Methods[] = {
@@ -287,7 +288,7 @@
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
     {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
-    {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+    {"nativeRenderPage", "(JJLandroid/graphics/Bitmap;IIIIJI)V", (void*) nativeRenderPage},
     {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
     {"nativeClosePage", "(J)V", (void*) nativeClosePage}
 };
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 5c2d0d0..bce2b33 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -618,23 +618,25 @@
 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    return getInternalFormat(nativeBitmap->colorType());
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    return getInternalFormat(nativeBitmap.colorType());
 }
 
 static jint util_getType(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    return getType(nativeBitmap->colorType());
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    return getType(nativeBitmap.colorType());
 }
 
 static jint util_texImage2D(JNIEnv *env, jclass clazz,
         jint target, jint level, jint internalformat,
         jobject jbitmap, jint type, jint border)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
         internalformat = getInternalFormat(colorType);
@@ -680,8 +682,8 @@
         jint target, jint level, jint xoffset, jint yoffset,
         jobject jbitmap, jint format, jint type)
 {
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     SkColorType colorType = bitmap.colorType();
     if (format < 0) {
         format = getInternalFormat(colorType);
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 3ae829b..50a1069 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -40,22 +40,21 @@
 
 // Native wrapper constructor used by Canvas(Bitmap)
 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
-    SkBitmap* bitmap = nullptr;
+    SkBitmap bitmap;
     if (jbitmap != NULL) {
-        bitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
+        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     }
-    return reinterpret_cast<jlong>(Canvas::create_canvas(
-            bitmap ? *bitmap : SkBitmap()));
+    return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
 }
 
 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
 // optionally copying canvas matrix & clip state.
 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
-    SkBitmap* bitmap = nullptr;
+    SkBitmap bitmap;
     if (jbitmap != NULL) {
-        bitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
+        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     }
-    get_canvas(canvasHandle)->setBitmap(bitmap ? *bitmap : SkBitmap());
+    get_canvas(canvasHandle)->setBitmap(bitmap);
 }
 
 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d86f71a..6afb226 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -26,6 +26,8 @@
 #include <utils/Log.h>
 #include <media/AudioRecord.h>
 
+#include <ScopedUtfChars.h>
+
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 
@@ -146,7 +148,7 @@
 static jint
 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
         jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
-        jint audioFormat, jint buffSizeInBytes, jintArray jSession)
+        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
 {
     //ALOGV(">> Entering android_media_AudioRecord_setup");
     //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
@@ -208,8 +210,10 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     // create an uninitialized AudioRecord object
-    sp<AudioRecord> lpRecorder = new AudioRecord();
+    sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
 
     audio_attributes_t *paa = NULL;
     // read the AudioAttributes values
@@ -587,9 +591,8 @@
 static jboolean android_media_AudioRecord_setInputDevice(
         JNIEnv *env,  jobject thiz, jint device_id) {
 
-//    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-//    return lpRecorder->setInputDevice(device_id) == NO_ERROR;
-    return false;
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    return lpRecorder->setInputDevice(device_id) == NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
@@ -598,7 +601,7 @@
     // name,               signature,  funcPtr
     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;IIIII[I)I",
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I",
                                        (void *)android_media_AudioRecord_setup},
     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index fc05a6d..3655adc 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -111,6 +111,7 @@
     jfieldID    mRouteFlags;
     jfieldID    mRegistrationId;
     jfieldID    mMixType;
+    jfieldID    mCallbackFlags;
 } gAudioMixFields;
 
 static jclass gAudioFormatClass;
@@ -149,6 +150,10 @@
     jmethodID    postEventFromNative;
 } gAudioPortEventHandlerMethods;
 
+static struct {
+    jmethodID postDynPolicyEventFromNative;
+} gDynPolicyEventHandlerMethods;
+
 static Mutex gLock;
 
 enum AudioError {
@@ -166,7 +171,7 @@
 #define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
 
 // ----------------------------------------------------------------------------
-// ref-counted object for callbacks
+// ref-counted object for audio port callbacks
 class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
 {
 public:
@@ -361,6 +366,26 @@
     env->DeleteLocalRef(clazz);
 }
 
+static void
+android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
+{
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        return;
+    }
+
+    jclass clazz = env->FindClass(kClassPathName);
+    const char* zechars = regId.string();
+    jstring zestring = env->NewStringUTF(zechars);
+
+    env->CallStaticVoidMethod(clazz, gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative,
+            event, zestring, val);
+
+    env->ReleaseStringUTFChars(zestring, zechars);
+    env->DeleteLocalRef(clazz);
+
+}
+
 static jint
 android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
 {
@@ -1402,7 +1427,11 @@
     return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
 }
 
-
+static void
+android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz)
+{
+    AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
+}
 
 
 static jint convertAudioMixToNative(JNIEnv *env,
@@ -1419,6 +1448,8 @@
     env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId);
     env->DeleteLocalRef(jRegistrationId);
 
+    nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
+
     jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
     nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
                                                      gAudioFormatFields.mSampleRate);
@@ -1567,7 +1598,8 @@
                                     (void *)android_media_AudioSystem_getAudioHwSyncForSession},
     {"registerPolicyMixes",    "(Ljava/util/ArrayList;Z)I",
                                             (void *)android_media_AudioSystem_registerPolicyMixes},
-
+    {"native_register_dynamic_policy_callback", "()V",
+                                    (void *)android_media_AudioSystem_registerDynPolicyCallback},
 };
 
 
@@ -1670,6 +1702,10 @@
     gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
                                                     eventHandlerClass, "mJniCallback", "J");
 
+    gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative =
+            GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
+                    "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
+
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
     gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
@@ -1680,6 +1716,7 @@
     gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
                                                       "Ljava/lang/String;");
     gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
+    gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
 
     jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
     gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 2f6a69c..26b82c5 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -35,6 +35,7 @@
 
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
+#include "android_media_PlaybackSettings.h"
 
 // ----------------------------------------------------------------------------
 
@@ -59,6 +60,7 @@
 };
 static audio_track_fields_t      javaAudioTrackFields;
 static audio_attributes_fields_t javaAudioAttrFields;
+static PlaybackSettings::fields_t gPlaybackSettingsFields;
 
 struct audiotrack_callback_cookie {
     jclass      audioTrack_class;
@@ -690,7 +692,7 @@
 
 // ----------------------------------------------------------------------------
 static void android_media_AudioTrack_set_playback_settings(JNIEnv *env,  jobject thiz,
-        jfloatArray floatArray, jintArray intArray) {
+        jobject settings) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
@@ -698,50 +700,39 @@
         return;
     }
 
-    // NOTE: Get<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
-    // TODO: consider the actual occupancy.
-    float farray[2];
-    int iarray[2];
-    if ((env->GetFloatArrayRegion(floatArray, 0, 2, farray), env->ExceptionCheck()) == JNI_FALSE
-            &&
-        (env->GetIntArrayRegion(intArray, 0, 2, iarray), env->ExceptionCheck()) == JNI_FALSE) {
-        // arrays retrieved OK
-        AudioPlaybackRate playbackRate;
-        playbackRate.mSpeed = farray[0];
-        playbackRate.mPitch = farray[1];
-        playbackRate.mFallbackMode = (AudioTimestretchFallbackMode)iarray[0];
-        playbackRate.mStretchMode = (AudioTimestretchStretchMode)iarray[1];
-        if (lpTrack->setPlaybackRate(playbackRate) != OK) {
-            jniThrowException(env, "java/lang/IllegalArgumentException",
-                    "arguments out of range");
-        }
+    PlaybackSettings pbs;
+    pbs.fillFromJobject(env, gPlaybackSettingsFields, settings);
+
+    ALOGV("setPlaybackSettings: %d:%f %d:%f %d:%u %d:%u",
+            pbs.speedSet, pbs.audioRate.mSpeed,
+            pbs.pitchSet, pbs.audioRate.mPitch,
+            pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
+            pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
+
+    if (lpTrack->setPlaybackRate(pbs.audioRate) != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                "arguments out of range");
     }
 }
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioTrack_get_playback_settings(JNIEnv *env,  jobject thiz,
-        jfloatArray floatArray, jintArray intArray) {
+static jobject android_media_AudioTrack_get_playback_settings(JNIEnv *env,  jobject thiz,
+        jobject settings) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "AudioTrack not initialized");
-        return;
+        return NULL;
     }
 
-    AudioPlaybackRate playbackRate = lpTrack->getPlaybackRate();
-
-    float farray[2] = {
-            playbackRate.mSpeed,
-            playbackRate.mPitch,
-    };
-    int iarray[2] = {
-            playbackRate.mFallbackMode,
-            playbackRate.mStretchMode,
-    };
-    // NOTE: Set<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
-    env->SetFloatArrayRegion(floatArray, 0, 2, farray);
-    env->SetIntArrayRegion(intArray, 0, 2, iarray);
+    PlaybackSettings pbs;
+    pbs.audioRate = lpTrack->getPlaybackRate();
+    pbs.speedSet = true;
+    pbs.pitchSet = true;
+    pbs.audioFallbackModeSet = true;
+    pbs.audioStretchModeSet = true;
+    return pbs.asJobject(env, gPlaybackSettingsFields);
 }
 
 
@@ -1012,9 +1003,11 @@
     {"native_get_playback_rate",
                              "()I",      (void *)android_media_AudioTrack_get_playback_rate},
     {"native_set_playback_settings",
-                             "([F[I)V",  (void *)android_media_AudioTrack_set_playback_settings},
+                             "(Landroid/media/PlaybackSettings;)V",
+                                         (void *)android_media_AudioTrack_set_playback_settings},
     {"native_get_playback_settings",
-                             "([F[I)V",  (void *)android_media_AudioTrack_get_playback_settings},
+                             "()Landroid/media/PlaybackSettings;",
+                                         (void *)android_media_AudioTrack_get_playback_settings},
     {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
     {"native_get_marker_pos","()I",      (void *)android_media_AudioTrack_get_marker_pos},
     {"native_set_pos_update_period",
@@ -1088,6 +1081,8 @@
     javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
             audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
 
+    env->DeleteLocalRef(audioTrackClass);
+
     // Get the AudioAttributes class and fields
     jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
     javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
@@ -1097,6 +1092,11 @@
     javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
             audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
 
+    env->DeleteLocalRef(audioAttrClass);
+
+    // initialize PlaybackSettings field info
+    gPlaybackSettingsFields.init(env);
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index e2bba30..9bc223b 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -134,8 +134,10 @@
 
 // ----------------------------------------------------------------------------
 
-static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
+static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr,
+        jstring opPackageNameStr) {
     ScopedUtfChars iface(env, ifaceStr);
+    ScopedUtfChars opPackageName(env, opPackageNameStr);
 
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
@@ -146,7 +148,7 @@
     }
 
     sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
-    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
+    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(String16(opPackageName.c_str()),
             client, String8(iface.c_str()));
     if (display == NULL) {
         ALOGE("Media player service rejected request to listen for remote display '%s'.",
@@ -176,7 +178,7 @@
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"nativeListen", "(Ljava/lang/String;)J",
+    {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
             (void*)nativeListen },
     {"nativeDispose", "(J)V",
             (void*)nativeDispose },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index cfbedda..fb82075 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -200,10 +200,8 @@
          * that can be made while an exception is pending, so we want to
          * get the VM ptr, throw the exception, and then detach the thread.
          */
-        JavaVM* vm = jnienv_to_javavm(env);
         env->Throw(excep);
-        vm->DetachCurrentThread();
-        sleep(60);
+        env->ExceptionDescribe();
         ALOGE("Forcefully exiting");
         exit(1);
     }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5cb8b2e..05bc125 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -40,6 +40,9 @@
 static jclass gLongClass;
 static jfieldID gLongValueID;
 
+static jclass gFloatClass;
+static jfieldID gFloatValueID;
+
 static jclass gStringClass;
 
 /*
@@ -66,6 +69,17 @@
 
 /*
  * In class android.util.EventLog:
+ *  static native int writeEvent(long tag, float value)
+ */
+static jint android_util_EventLog_writeEvent_Float(JNIEnv* env UNUSED,
+                                                  jobject clazz UNUSED,
+                                                  jint tag, jfloat value)
+{
+    return android_btWriteLog(tag, EVENT_TYPE_FLOAT, &value, sizeof(value));
+}
+
+/*
+ * In class android.util.EventLog:
  *  static native int writeEvent(int tag, String value)
  */
 static jint android_util_EventLog_writeEvent_String(JNIEnv* env,
@@ -128,6 +142,12 @@
             buf[pos++] = EVENT_TYPE_LONG;
             memcpy(&buf[pos], &longVal, sizeof(longVal));
             pos += sizeof(longVal);
+        } else if (env->IsInstanceOf(item, gFloatClass)) {
+            jfloat floatVal = env->GetFloatField(item, gFloatValueID);
+            if (pos + 1 + sizeof(floatVal) > max) break;
+            buf[pos++] = EVENT_TYPE_FLOAT;
+            memcpy(&buf[pos], &floatVal, sizeof(floatVal));
+            pos += sizeof(floatVal);
         } else {
             jniThrowException(env,
                     "java/lang/IllegalArgumentException",
@@ -233,6 +253,7 @@
     /* name, signature, funcPtr */
     { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
     { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
+    { "writeEvent", "(IF)I", (void*) android_util_EventLog_writeEvent_Float },
     { "writeEvent",
       "(ILjava/lang/String;)I",
       (void*) android_util_EventLog_writeEvent_String
@@ -251,6 +272,7 @@
     { "android/util/EventLog$Event", &gEventClass },
     { "java/lang/Integer", &gIntegerClass },
     { "java/lang/Long", &gLongClass },
+    { "java/lang/Float", &gFloatClass },
     { "java/lang/String", &gStringClass },
     { "java/util/Collection", &gCollectionClass },
 };
@@ -258,6 +280,7 @@
 static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
     { &gIntegerClass, "value", "I", &gIntegerValueID },
     { &gLongClass, "value", "J", &gLongValueID },
+    { &gFloatClass, "value", "F", &gFloatValueID },
 };
 
 static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 6bcc92e..a362684 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -112,8 +112,7 @@
         jlong rendererPtr, jlong functorPtr) {
     DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    android::uirenderer::Rect dirty;
-    renderer->callDrawGLFunction(functor, dirty);
+    renderer->callDrawGLFunction(functor);
 }
 
 // ----------------------------------------------------------------------------
@@ -212,12 +211,10 @@
 }
 
 static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong renderNodePtr,
-        jint flags) {
+        jobject clazz, jlong rendererPtr, jlong renderNodePtr) {
     DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    android::uirenderer::Rect bounds;
-    renderer->drawRenderNode(renderNode, bounds, flags);
+    renderer->drawRenderNode(renderNode);
 }
 
 // ----------------------------------------------------------------------------
@@ -283,7 +280,7 @@
     { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
 
     { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
-    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_DisplayListCanvas_drawRenderNode },
+    { "nDrawRenderNode",    "(JJ)V",           (void*) android_view_DisplayListCanvas_drawRenderNode },
 
     { "nCreateDisplayListCanvas", "()J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
 
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index f6d9a1a..d04adbf 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -80,10 +80,7 @@
 
     jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
     if (bitmapObj) {
-        SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj);
-        if (bitmap) {
-            outPointerIcon->bitmap = *bitmap; // use a shared pixel ref
-        }
+        GraphicsJNI::getSkBitmap(env, bitmapObj, &(outPointerIcon->bitmap));
         env->DeleteLocalRef(bitmapObj);
     }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 11b3805..4ccbb41 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -21,6 +21,7 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include "core_jni_helpers.h"
+#include <GraphicsJNI.h>
 #include <ScopedPrimitiveArray.h>
 
 #include <EGL/egl.h>
@@ -347,10 +348,11 @@
 }
 
 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+        jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     return proxy->copyLayerInto(layer, bitmap);
 }
 
@@ -458,7 +460,7 @@
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
-    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+    { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 7080e2a..baeb7dd 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -277,8 +277,9 @@
     EGLConfig  cnf = getConfig(_env, config);
     jint* base = 0;
 
-    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap);
-    SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
+    SkBitmap nativeBitmap;
+    GraphicsJNI::getSkBitmap(_env, native_pixmap, &nativeBitmap);
+    SkPixelRef* ref = nativeBitmap.pixelRef();
     if (ref == NULL) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
         return;
@@ -289,10 +290,10 @@
 
     egl_native_pixmap_t pixmap;
     pixmap.version = sizeof(pixmap);
-    pixmap.width  = nativeBitmap->width();
-    pixmap.height = nativeBitmap->height();
-    pixmap.stride = nativeBitmap->rowBytes() / nativeBitmap->bytesPerPixel();
-    pixmap.format = convertPixelFormat(nativeBitmap->colorType());
+    pixmap.width  = nativeBitmap.width();
+    pixmap.height = nativeBitmap.height();
+    pixmap.stride = nativeBitmap.rowBytes() / nativeBitmap.bytesPerPixel();
+    pixmap.format = convertPixelFormat(nativeBitmap.colorType());
     pixmap.data   = (uint8_t*)ref->pixels();
 
     base = beginNativeAttribList(_env, attrib_list);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 018c1a1..942e6a6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -79,6 +79,8 @@
 
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
+    <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
@@ -1178,13 +1180,13 @@
     <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
         android:protectionLevel="system|signature" />
 
-    <!-- @SystemApi Allows an application to bind to InCallService implementations.
-         @hide -->
+    <!-- Must be required by a {@link android.telecom.InCallService},
+         to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:protectionLevel="system|signature" />
 
-    <!-- @SystemApi Allows an application to bind to ConnectionService implementations.
-         @hide -->
+    <!-- Must be required by a {@link android.telecom.ConnectionService},
+         to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
         android:protectionLevel="system|signature" />
 
diff --git a/core/res/res/color/primary_text_activated_material_dark.xml b/core/res/res/color/primary_text_activated_material_dark.xml
deleted file mode 100644
index f1b742a..0000000
--- a/core/res/res/color/primary_text_activated_material_dark.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true"
-          android:color="@color/primary_text_default_material_light"/>
-    <item android:color="@color/primary_text_default_material_dark"/>
-</selector>
diff --git a/core/res/res/color/primary_text_activated_material_light.xml b/core/res/res/color/primary_text_activated_material_light.xml
deleted file mode 100644
index d92da63..0000000
--- a/core/res/res/color/primary_text_activated_material_light.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true"
-          android:color="@color/primary_text_default_material_dark"/>
-    <item android:color="@color/primary_text_default_material_light"/>
-</selector>
diff --git a/core/res/res/color/primary_text_inverse_when_activated_material.xml b/core/res/res/color/primary_text_inverse_when_activated_material.xml
new file mode 100644
index 0000000..0f7f9cdf
--- /dev/null
+++ b/core/res/res/color/primary_text_inverse_when_activated_material.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_enabled="false"
+        android:state_activated="true"
+        android:color="?attr/textColorPrimaryInverse"
+        android:alpha="?attr/disabledAlpha" />
+    <item
+        android:state_enabled="false"
+        android:color="?attr/textColorPrimary"
+        android:alpha="?attr/disabledAlpha" />
+    <item
+        android:state_activated="true"
+        android:color="?attr/textColorPrimaryInverse" />
+    <item
+        android:color="?attr/textColorPrimary" />
+</selector>
diff --git a/core/res/res/color/secondary_text_activated_material_dark.xml b/core/res/res/color/secondary_text_activated_material_dark.xml
deleted file mode 100644
index 7a8428a..0000000
--- a/core/res/res/color/secondary_text_activated_material_dark.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true"
-          android:color="@color/secondary_text_default_material_light"/>
-    <item android:color="@color/secondary_text_default_material_dark"/>
-</selector>
diff --git a/core/res/res/color/secondary_text_activated_material_light.xml b/core/res/res/color/secondary_text_activated_material_light.xml
deleted file mode 100644
index 36ff408..0000000
--- a/core/res/res/color/secondary_text_activated_material_light.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true"
-          android:color="@color/secondary_text_default_material_dark"/>
-    <item android:color="@color/secondary_text_default_material_light"/>
-</selector>
diff --git a/core/res/res/color/secondary_text_inverse_when_activated_material.xml b/core/res/res/color/secondary_text_inverse_when_activated_material.xml
new file mode 100644
index 0000000..5b259de
--- /dev/null
+++ b/core/res/res/color/secondary_text_inverse_when_activated_material.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_enabled="false"
+        android:state_activated="true"
+        android:color="?attr/textColorSecondaryInverse"
+        android:alpha="?attr/disabledAlpha" />
+    <item
+        android:state_enabled="false"
+        android:color="?attr/textColorSecondary"
+        android:alpha="?attr/disabledAlpha" />
+    <item
+        android:state_activated="true"
+        android:color="?attr/textColorSecondaryInverse" />
+    <item
+        android:color="?attr/textColorSecondary" />
+</selector>
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 41caa4e..7cb1b89 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -15,15 +15,24 @@
 -->
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true" android:id="@+id/on"
+
+    <item
+        android:id="@+id/on"
+        android:state_checked="true"
         android:drawable="@drawable/ic_checkbox_checked" />
-    <item android:id="@+id/off"
+
+    <item
+        android:id="@+id/off"
         android:drawable="@drawable/ic_checkbox_unchecked" />
 
-    <transition android:fromId="@+id/off" android:toId="@+id/on"
+    <transition
+        android:fromId="@+id/off"
+        android:toId="@+id/on"
         android:drawable="@drawable/ic_checkbox_unchecked_animation" />
 
-    <transition android:fromId="@+id/on" android:toId="@+id/off"
+    <transition
+        android:fromId="@+id/on"
+        android:toId="@+id/off"
         android:drawable="@drawable/ic_checkbox_checked_animation" />
-</animated-selector>
 
+</animated-selector>
diff --git a/core/res/res/drawable/ic_checkbox_checked.xml b/core/res/res/drawable/ic_checkbox_checked.xml
index 4764115..cc7b5df 100644
--- a/core/res/res/drawable/ic_checkbox_checked.xml
+++ b/core/res/res/drawable/ic_checkbox_checked.xml
@@ -22,7 +22,7 @@
     android:viewportWidth="48"
     android:height="32dp"
     android:viewportHeight="48"
-    android:tint="?attr/colorControlNormal" >
+    android:tint="?attr/colorControlActivated" >
     <group
         android:name="icon_null"
         android:translateX="24"
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index e1af94c..c2b4ccc 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -24,4 +24,4 @@
     android:elevation="2dp"
     android:focusable="true"
     android:focusableInTouchMode="true"
-    android:background="@color/floating_toolbar_background_color"/>
+    android:background="?attr/colorBackgroundFloating"/>
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index 70227fa..23ae7f0 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -29,5 +29,5 @@
     android:fontFamily="sans-serif"
     android:textSize="@dimen/floating_toolbar_text_size"
     android:textAllCaps="true"
-    android:textColor="@color/floating_toolbar_text_color"
+    android:textColor="?attr/colorForeground"
     android:background="?attr/selectableItemBackground" />
diff --git a/core/res/res/layout/floating_popup_overflow_list_item b/core/res/res/layout/floating_popup_overflow_list_item
index c0db1bd..59a6d7e 100644
--- a/core/res/res/layout/floating_popup_overflow_list_item
+++ b/core/res/res/layout/floating_popup_overflow_list_item
@@ -31,5 +31,5 @@
     android:ellipsize="end"
     android:fontFamily="sans-serif"
     android:textSize="@dimen/floating_toolbar_text_size"
-    android:textColor="@color/floating_toolbar_text_color"
+    android:textColor="?attr/colorForeground"
     android:textAllCaps="true" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6fc1a45..ad596db 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Stel op"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Haal uit"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Verken"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Geen passende aktiwiteite gevind nie."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Roeteer media-uitvoer"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Laat \'n program toe om media-uitvoere na ander eksterne toestelle te roeteer."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 6a3d0c2..827d662 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"አዋቅር"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"አስወጣ"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"ያስሱ"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"ምንም ተመሳሳይ እንቅስቃሴዎች አልተገኙም።"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"የሚዲያ ውፅአት መንገድ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"አንድ መተግበሪያ የሚዲያ ውፅአትን ወደ ሌላ ውጫዊ መሳሪያ እንዲመራ ይፈቅድለታል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index fc83bb6a..9b3672a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1106,6 +1106,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"الإعداد"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"إلغاء"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"استكشاف"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"لم يتم العثور على أي أنشطة متطابقة."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"توجيه إخراج الوسائط"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"للسماح للتطبيق بتوجيه إخراج الوسائط إلى أجهزة خارجية أخرى."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d60e0f0..a7a4742 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Настройване"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Изваждане"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Изследване"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Не бяха намерени съответстващи дейности."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Насочване на изходящата мултимедия"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Разрешава на приложението да насочва изходящата мултимедия към други външни устройства."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index d61965a..af2eb07 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"সেটআপ"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"বের করে নিন"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"ঘুরে দেখুন"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"কোনো সমরূপ কার্যকলাপ খুঁজে পাওয়া যায়নি৷"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"মিডিয়া আউটপুট রুট করুন"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"অ্যাপ্লিকেশানটিকে অন্যান্য বহিরাগত ডিভাইসে মিডিয়া আউটপুট রুট করার অনুমতি দেয়৷"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d1eda0e..394c520 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configura"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Expulsa"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explora"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No s\'ha trobat cap activitat coincident."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Indicació de ruta de sortida de contingut multimèdia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permet que una aplicació indiqui la ruta de sortida de contingut multimèdia a altres dispositius externs."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ed5b413..90d0ba2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Nastavení"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Odpojit"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Prozkoumat"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nebyly nalezeny žádné odpovídající aktivity."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Směrování výstupu médií"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Umožňuje aplikaci směrovat výstup médií do dalších externích zařízení."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9918b08..7ec459f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Konfigurer"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Skub ud"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Udforsk"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Der blev ikke fundet nogen matchende aktiviteter."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Viderefør medieoutput"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Tillader, at en applikation viderefører medieoutput til andre eksterne enheder."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cea19ac..4bd91f2 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Einrichten"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Auswerfen"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Entdecken"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Keine passenden Aktivitäten gefunden"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht der App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0f9ada3..836ed89 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Ρύθμιση"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Εξαγωγή"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Εξερεύνηση"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Δεν βρέθηκαν δραστηριότητες που να συμφωνούν με τα κριτήρια."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Διαγραφή διαδρομής δεδομένων εξόδου μέσων"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Επιτρέπει σε μια εφαρμογή τη διαγραφή διαδρομής δεδομένων εξόδου μέσων σε άλλες εξωτερικές συσκευές."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 4c7e534..031f165 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Set up"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Eject"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explore"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No matching activities found."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Route media output"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Allows an application to route media output to other external devices."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4c7e534..031f165 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Set up"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Eject"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explore"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No matching activities found."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Route media output"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Allows an application to route media output to other external devices."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 4c7e534..031f165 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Set up"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Eject"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explore"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No matching activities found."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Route media output"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Allows an application to route media output to other external devices."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5a04b8b..656abbf 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configuración"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Expulsar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorar"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No se encontraron actividades coincidentes."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Dirigir salida de medios"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que la aplicación dirija salidas de medios a otros dispositivos externos."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f05757d..fe8c676 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configurar"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Expulsar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorar"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"No se ha encontrado ninguna actividad coincidente."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Dirigir salida de medio"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que la aplicación dirija salidas de medios a otros dispositivos externos."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 9ee98df..7259886 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Seadistamine"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Eemaldamine"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Avastamine"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Sobivat tegevust ei leitud"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Meediaväljundi teekonna koostamine"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Võimaldab rakendusel koostada teekonna meediaväljundist teistesse välistesse seadmetesse."</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 31371d0..f12151c 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Konfigurazioa"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Atera"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Arakatu"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Ez da bat datorren jarduerarik aurkitu."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Multimedia-irteera bideratzea"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Multimedia elementuak kanpoko gailuetara bideratzeko baimena ematen die aplikazioei."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6e831f5..2808a78 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"تنظیم"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"بیرون راندن"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"کاوش"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"فعالیتی مطابق با این مورد یافت نشد."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"تعیین مسیر خروجی رسانه"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"به یک برنامه اجازه می‌دهد خروجی رسانه را به دستگاه‌های خارجی دیگر تعیین مسیر کند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index cb0f601..1d71bd1 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Asennus"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Poista"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Tutustu"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Osuvia toimintoja ei löytynyt."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Median reititys"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Antaa sovelluksen reitittää mediaa muihin ulkoisiin laitteisiin."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9bed850..2b81a18 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configuration"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Éjecter"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Découvrir"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Aucune activité correspondante trouvée."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Diriger la sortie multimédia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permet à une application de diriger la sortie multimédia vers d\'autres appareils externes."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b46f4d5..55c4f5d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configurer"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Éjecter"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Parcourir"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Aucune activité correspondante trouvée."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Diriger la sortie multimédia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permet à une application de diriger la sortie multimédia vers d\'autres appareils externes."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index ca089bb..c2c67bc 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configuración"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Expulsar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorar"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Non se atoparon actividades que coincidan."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Dirixir saída multimedia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite a unha aplicación dirixir a saída multimedia a outros dispositivos externos."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 9f90ed6..5d954e2 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"सेट करें"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"निकालें"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"एक्सप्लोर करें"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"कोई मिलती-जुलती गतिविधि नहीं मिली."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"मीडिया आउटपुट को रूट करें"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"ऐप्स  को मीडिया आउटपुट को अन्य बाहरी डिवाइस पर रूट करने देता है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index a340ac6..cf81cd1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1085,6 +1085,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Postavljanje"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Izbaci"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Istražite"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nisu pronađene podudarne radnje."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Usmjeravanje medijskog izlaza"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Aplikaciji omogućuje usmjeravanje medijskog izlaza na druge vanjske uređaje."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f1db0a8..ae606b2 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Beállítás"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Kiadás"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Felfedezés"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nincs megfelelő tevékenység."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Médiafájlok kimenetének irányítása"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Lehetővé teszi az alkalmazás számára, hogy más külső eszközökre irányítsa a médiafájlok lejátszását."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 3807578..f393c87 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Կարգավորում"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Անջատել"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Ուսումնասիրել"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Համընկնող գործունեություններ չգտնվեցին:"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Երթուղել մեդիա արտածումը"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Թույլ է տալիս հավելվածին մեդիա արտածումը երթուղել այլ արտաքին սարքեր:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 59f48cc..298f204 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Siapkan"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Keluarkan"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Jelajahi"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Tidak ditemukan aktivitas yang sesuai."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Menentukan rute keluaran media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Memungkinkan aplikasi menentukan rute keluaran media ke perangkat eksternal lainnya."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index a234eb4..b36322b 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Uppsetning"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Fjarlægja"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Kanna"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Engar aðgerðir með samsvörun fundust."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Beina margmiðlunarúttaki"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Leyfir forriti að beina margmiðlunarúttaki til annarra ytri tækja."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a3ae79d..5a2bf7a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configura"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Espelli"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Scopri"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nessuna attività corrispondente trovata."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Indirizzamento uscita media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Consente a un\'applicazione di indirizzare l\'uscita di media verso altri dispositivi esterni."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 6031b04..0f2a691 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"הגדר"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"הוצא"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"גלה"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"לא נמצאו פעילויות תואמות."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"ניתוב פלט מדיה"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"מאפשר לאפליקציה לנתב פלט מדיה למכשירים חיצוניים אחרים."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9c77257..71eec56 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"セットアップ"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"取り外し"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"外部メディア"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"一致するアクティビティが見つかりません。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"メディア出力のルーティング"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"メディア出力を他の外部デバイスにルーティングすることをアプリに許可します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index b270ee3..1fc1b95 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"დაყენება"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"გამოღება"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"დათვალიერება"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"შესატყვისი აქტივობები არ არის."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"მულტიმედია მონაცემების გადამისამართება"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"აპლიკაციას შეეძლება გადაამისამართოს მულტიმედია მონაცემები სხვა გარე მოწყობილობებისკენ."</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index fc88343..5808e6d 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Орнату"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Шығару"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Зерттеу"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Сәйкес әрекеттер табылмады."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Медиа шығысын бағыттау"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Қолданбаға медиа шығысын басқа сыртқы құрылғыларға бағыттау мүмкіндігін береді."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index eeee275..423506f 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1080,6 +1080,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ដំឡើង"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"ដកចេញ"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"រុករក"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"រក​មិន​ឃើញ​សកម្មភាព​ផ្គូផ្គង។"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"នាំ​ផ្លូវ​លទ្ធផល​មេឌៀ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"ឲ្យ​កម្មវិធី​នាំ​ផ្លូវ​លទ្ធផល​មេឌៀ​ទៅ​ឧបករណ៍​​ខាង​ក្រៅ​ផ្សេង។"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 125625f..eca6ee8 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ಸೆಟಪ್"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"ಎಜೆಕ್ಟ್ ಮಾಡು"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"ಎಕ್ಸ್‌ಪ್ಲೋರ್‌‌"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಯ ಚಟುವಟಿಕೆಗಳು ಕಂಡುಬಂದಿಲ್ಲ."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"ಮೀಡಿಯಾ ಔಟ್‍ಪುಟ್ ಅನ್ನು ರೂಟ್ ಮಾಡಿ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"ಇತರ ಬಾಹ್ಯ ಸಾಧನಗಳಿಗೆ ಮೀಡಿಯಾ ಔಟ್‍‍ಪುಟ್ ಅನ್ನು ರೂಟ್ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4687d1d..853a6ed 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"앱이 WAP 메시지를 수신하고 처리할 수 있도록 허용합니다. 이는 앱이 사용자에게 표시하지 않고 기기로 전송된 메시지를 모니터링 또는 삭제할 수도 있다는 것을 의미합니다."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"실행 중인 앱 검색"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 허용합니다. 이 경우 앱이 기기에서 사용되는 다른 앱에 대한 정보를 검색할 수 있습니다."</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"프로필 및 기기 소유자 관리"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"앱이 프로필 소유자와 기기 소유자를 설정하도록 허용합니다."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"실행 중인 앱 순서 재지정"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"앱이 사용자의 입력 없이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"운전모드 사용"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"설정"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"꺼내기"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"둘러보기"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"일치하는 활동이 없습니다."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"미디어 출력 연결"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"앱이 미디어 출력을 기타 외부 기기에 연결할 수 있도록 허용합니다."</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 4fe2cfb..ee87665 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1430,6 +1430,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Орнотуу"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Чыгаруу"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Изилдөө"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Туура келген аракеттер табылбады."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Медиа чыгарылышын багыттоо"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Колдонмого  медиа мазмунду башка тышкы түзмөктөргө багыттоо уруксатын берет."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 0453de9..5128827 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ຕິດຕັ້ງ"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"ເອົາອອກ"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"ຄົ້ນຫາ"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"ບໍ່ພົບກິດຈະກຳທີ່ກົງກັນ."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"ກຳນົດເສັ້ນທາງເອົ້າພຸດຂອງສື່"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ກຳນົດເສັ້ນທາງເອົ້າພຸດຂອງສື່ໄປຫາອຸປະກອນພາຍນອກອື່ນໆ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 30c1610..ededc9a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Sąranka"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Pašalinti"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Naršyti"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nerasta atitinkančios veiklos."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medijos išvesties nukreipimas"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Leidžiama programai nukreipti medijos išvestį į kitus išorinius įrenginius."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index bdefa64..9110e70 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1085,6 +1085,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Iestatīt"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Izstumt"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Izpētīt"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nav atrasta neviena atbilstoša darbība."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Multivides datu izejas maršrutēšana"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ļauj lietojumprogrammai maršrutēt multivides datu izeju uz citām ārējām ierīcēm."</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 3ce3cf0..4f5c913 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Поставување"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Извади"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Истражувај"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Не се пронајдени соодветни активности."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Насочи излез за медиуми"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Овозможува апликацијата да насочува излез за медиуми кон други надворешни уреди."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 0631b73..62c5b1f 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"സജ്ജമാക്കുക"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"നിരസിക്കുക"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"പര്യവേക്ഷണം ചെയ്യുക"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"പൊരുത്തമുള്ള പ്രവർത്തനങ്ങളൊന്നും കണ്ടെത്തിയില്ല."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"മീഡിയ ഔട്ട്പുട്ട് റൂട്ടുചെയ്യുക"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"മീഡിയ ഔട്ട്‌പുട്ടിനെ മറ്റ് ബാഹ്യ ഉപകരണങ്ങളിലേക്ക് റൂട്ടുചെയ്യാൻ ഒരു അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 45576c1..971a6a8 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Тохируулга"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Салгах"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Судлах"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Таарах активити олдсонгүй."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Медиа гаралтыг чиглүүлэх"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Аппликешн нь медиа гаралтыг бусад гадаад төхөөрөмжрүү чиглүүлэх боломжтой."</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index e52fe37..8bca6a5 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"सेटअप"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"बाहेर काढा"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"एक्सप्लोर करा"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"कोणतेही जुळणारे क्रियाकलाप आढळले नाहीत."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"मीडिया आउटपुट मार्गस्थ करा"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"अन्य बाह्य डिव्हाइसेसवरील रूट मीडिया आउटपुट वर अनुप्रयोगास अनुमती देते."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 7d3a314..f068fcd 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Persediaan"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Tanggalkan"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Teroka"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Tiada aktiviti yang sepadan ditemui."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Buat laluan output media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Membenarkan apl untuk membuat laluan output media ke peranti luaran lain."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index ffcf6b8..e315f56c 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"စဖွင့်သတ်မှတ်ရန်"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"ထုတ်မည်"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"စူးစမ်းရန်"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"တိုက်ဆိုင်သော ပြုလုပ်ချက် ရှာမတွေ့ပါ"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"မီဒီယာထွက်ပေါက်အား လမ်းလွှဲပြောင်းခြင်း"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"အပလီကေးရှင်းအား မီဒီယာ ထုတ်လွှတ်မှုကို အခြားပြင်ပ စက်ပစ္စည်းများသို့ လွှဲပြောင်းခွင့်ပြုပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 47ff2a0..9f0f3b6 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Konfigurering"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Løs ut"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Utforsk"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Finner ingen samsvarende aktiviteter."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Videresending av medieutdata"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Lar en app videresende medieutdata til andre eksterne enheter."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 7591e80..66f8ae2 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1074,11 +1074,11 @@
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string>
-    <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"फोटोहरू र मिडिया स्थानान्तरणका लागि"</string>
+    <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"तस्बिरहरू र मिडिया स्थानान्तरणका लागि"</string>
     <string name="ext_media_unmountable_notification_title" msgid="4863279349863279603">"<xliff:g id="NAME">%s</xliff:g> बिग्रेको छ।"</string>
-    <string name="ext_media_unmountable_notification_message" msgid="7391672496565685690">"<xliff:g id="NAME">%s</xliff:g> बिग्रेको छ; यसलाई पुनः फर्म्याट गर्न प्रयास गर्नुहोस्"</string>
+    <string name="ext_media_unmountable_notification_message" msgid="7391672496565685690">"<xliff:g id="NAME">%s</xliff:g> बिग्रेको छ; यसलाई पुनः ढाँचा गर्न प्रयास गर्नुहोस्"</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"<xliff:g id="NAME">%s</xliff:g> अप्रत्याशित रूपमा निकालियो"</string>
-    <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"डेटा नोक्सानबाट बच्न निकाल्नु अघि <xliff:g id="NAME">%s</xliff:g> अनमाउन्ट गर्नुहोस्"</string>
+    <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"डेटा हराउनबाट जोगाउन निकाल्नु अघि <xliff:g id="NAME">%s</xliff:g> अनमाउन्ट गर्नुहोस्"</string>
     <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"निकालियो <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"<xliff:g id="NAME">%s</xliff:g> निकालियो; नयाँ हाल्नुहोस्"</string>
     <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"अझै निकाल्दै <xliff:g id="NAME">%s</xliff:g>..."</string>
@@ -1086,6 +1086,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"सेटअप"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"निकाल्नुहोस्"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"अन्वेषण गर्नुहोस्"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"कुनै मिल्ने गतिविधि पाइएन।"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"मिडिया परिणाम दिशानिर्देश गर्नुहोस्"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"मिडिया परिणामलाई अन्य बाहिरी उपकरणहरूसँग लैजानको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f5d5e8e..7391d4b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configuratie"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Uitwerpen"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Verkennen"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Geen overeenkomende activiteiten gevonden."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Media-uitvoer aansturen"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Hiermee kan een app media-uitvoer naar andere externe apparaten doorsturen."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e4aca19..d87fd22 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Skonfiguruj"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Wysuń"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Przeglądaj"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nie znaleziono pasujących działań."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Kierowanie wyjścia multimediów"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Pozwala aplikacji na kierowanie wyjściowych danych multimedialnych do innych urządzeń zewnętrznych."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e75620b..28c14da 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configuração"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Ejetar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorar"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Não foi encontrada nenhuma atividade correspondente."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Encaminhar saída de som multimédia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que a aplicação encaminhe a saída de som multimédia para outros dispositivos externos."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f2c8527..b1551b0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configurar"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Ejetar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorar"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nenhum atividade correspondente foi encontrada."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Rotear saída de mídia"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite que um app faça o roteamento de saída de mídia para outros dispositivos externos."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index df7e778..1790122 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1085,6 +1085,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Configurați"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Scoateți"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Explorați"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nu s-a găsit nicio activitate potrivită."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcţionează rezultatele media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcţioneze rezultate media către alte dispozitive externe."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8b6d913..b9eab57 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Настроить"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Извлечь"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Обзор"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Подходящих действий не найдено."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Перенаправление мультимедийных данных"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Приложение сможет направлять поток мультимедиа на другие внешние устройства."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 56e1576..f21d99e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1080,6 +1080,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ස්ථාපනය"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"ගැලවීම"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"ගවේෂණය කරන්න"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"ගැලපෙන ක්‍රියාකාරකම් හමු නොවුණි."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"මාධ්‍ය ප්‍රතිදානයේ මාර්ගගත කිරීම"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"වෙනත් බාහිර උපාංග වෙත මාධ්‍ය ප්‍රතිදානය යැවීමට යෙදුමට අවසර දෙන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 498dcde..8e97275 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Nastavenie"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Odpojiť"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Preskúmať"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Nenašli sa žiadne zodpovedajúce aktivity."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Smerovanie výstupu médií"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Umožňuje aplikácii smerovať výstup médií do ďalších externých zariadení."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 77f9a1f..0ed81d3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Nastavitev"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Izvrzite"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Raziščite"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Ni ustreznih dejavnosti."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Preusmeritev predstavnosti"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Aplikaciji omogoča preusmerjanje predstavnosti v druge zunanje naprave."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e3e6f1d..c18d98f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1085,6 +1085,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Подешавање"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Избаци"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Истражи"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Није пронађена ниједна подударна активност."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Усмеравање излаза медија"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дозвољава апликацији да усмерава излаз медија на друге спољне уређаје."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b78e632..6981717 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Konfiguration"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Mata ut"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Utforska"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Det gick inte att hitta några matchande aktiviteter."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Omdirigera medieuppspelning"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Tillåter att appen omdirigerar medieuppspelningar till andra externa enheter."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8c58d5b..e807ca1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Sanidi"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Ondoa"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Chunguza"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Hakuna shughuli zinazolingana zilizopatikana."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Fuatalia utoaji wa habari"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Inaruhusu programu kufuatilia utoaji wa habari kwa vifaa vingine vya nje."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index a33af51..f07fcac 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"அமைவு"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"வெளியேற்று"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"உலாவுக"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"பொருந்தும் செயல்பாடுகள் கண்டறியப்படவில்லை."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"மீடியா அவுட்புட்டை வழிசெலுத்துதல்"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"மீடியாவைப் பிற வெளிப்புறச் சாதனங்களுக்கு வெளியீடாக வழிகாட்ட பயன்பாட்டை அனுமதிக்கிறது."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 6bd4007..a36c8fe 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"సెటప్ చేయి"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"తొలగించు"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"విశ్లేషించు"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"సరిపోలే కార్యాచరణలు కనుగొనబడలేదు."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"ప్రసార మాధ్యమ అవుట్‌పుట్‌ను మళ్లించడం"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"మీడియా అవుట్‌పుట్‌ను ఇతర బాహ్య పరికరాలకు మళ్లించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 501ce0a..84d31a3 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ตั้งค่า"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"นำอุปกรณ์ออก"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"สำรวจ"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"ไม่พบกิจกรรมที่ตรงกัน"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"กำหนดเส้นทางเอาต์พุตของสื่อ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"อนุญาตให้แอปพลิเคชันกำหนดเส้นทางเอาต์พุตของสื่อไปยังอุปกรณ์ภายนอกอื่นๆ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 545bcd5..e343404 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"I-setup"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"I-eject"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"I-explore"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Walang nahanap na mga tumutugmang aktibidad."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"I-route ang output ng media"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Pinapayagan ang application na mag-route ng output ng media sa iba pang mga panlabas na device."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index fa2405e..c9166cd 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Uygulamaya WAP mesajlarını alma ve işleme izni verir. Buna, size gönderilen mesajları takip edip size göstermeden silebilme izni de dahildir."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"çalışan uygulamaları al"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Uygulamaya o anda ve son çalışan görevler hakkında bilgi alma izni verir. Bu izin, uygulamanın cihaz tarafından kullanılan uygulamalar hakkında bilgi elde etmesine olanak sağlayabilir."</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"Profil ve cihaz sahiplerini yönetme"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Uygulamaların, profil sahiplerini ve cihaz sahibini ayarlamasına izin verir."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"çalışan uygulamaları yeniden sırala"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Uygulama bunu sizden bir giriş olmadan yapabilir."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"araç modunu etkinleştir"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Kurulum"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Çıkar"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Keşfedin"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Eşleşen hiçbir etkinlik bulunamadı."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medya çıktısını yönlendir"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Uygulamaya medya çıktısını başka harici cihazlara yönlendirme izni verir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 527f09a..81c24a4 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1092,6 +1092,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Налаштувати"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Відключити"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Переглянути"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Відповідні дії не знайдено."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Скеровувати вивід медіа-даних"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дозволяє програмі скеровувати вивід медіа-даних на інші зовнішні пристрої."</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index a9d7572..03ad6ac 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"‏ایپ کو WAP پیغامات حاصل اور ان پر کارروائی کرنے کی اجازت دیتا ہے۔ اس اجازت میں آپ کو مرسلہ پیغامات آپ کو دکھائے بغیر ان پر نگاہ رکھنے یا انہیں حذف کرنے کی اہلیت شامل ہے۔"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"چل رہی ایپس کی بازیافت کریں"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ایپ کو موجودہ اور حالیہ چل رہے ٹاسکس کے بارے میں معلومات بازیافت کرنے کی اجازت دیتا ہے۔ یہ ایپ کو اس بارے میں معلومات دریافت کرنے کی اجازت دے سکتا ہے کہ آلہ پر کون سی ایپلیکیشنز استعمال کی جاتی ہیں۔"</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"پروفائل اور آلہ کے مالکان کا نظم کریں"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"ایپس کو پروفائل کے مالکان اور آلہ کے مالک کو سیٹ کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"چل رہی ایپس کو دوبارہ ترتیب دیں"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"ایپ کو پیش منظر یا پس منظر میں ٹاسکس کو منتقل کرنے کی اجازت دیتا ہے۔ ایپ آپ کے ان پٹ کے بغیر یہ کام کرسکتی ہے۔"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"کار وضع فعال کریں"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"ترتیب دیں"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"خارج کریں"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"دریافت کریں"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"کوئی مماثل سرگرمیاں نہیں ملیں۔"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"میڈیا آؤٹ پٹ کی سمت طے کریں"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"کسی ایپلیکیشن کو دوسرے خارجی آلات تک میڈیا آؤٹ پٹ کا راستہ بنانے کی اجازت دیتا ہے۔"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index ec1a840..9706535 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -275,7 +275,7 @@
     <string name="permlab_getTasks" msgid="6466095396623933906">"ishlab turgan ilovalar to‘g‘risida ma’lumot olish"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ilovaga hozirda va so‘nggi ishga tushirilgan vazifalar haqida to‘liq ma’lumot olishiga ruxsat beradi. Bu ilovaga qurilmadagi ishlatilayotgan ilovalar haqidagi ma’lumotlarga ega bo‘lishiga ruxsat berishi mumkin."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"Profil va qurilma egalarini boshqarish"</string>
-    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Ilovaga profil va qurilma egalarini sozlash uchun ruxsat beradi"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Ilovaga profil egalari va qurilma egalarini aniqlash uchun ruxsat beradi."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"ishlab turgan ilovalarni qayta tartiblash"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ilovalarga vazifalarni old va orqa fonga o‘tkazish uchun ruxsat beradi. Ilova buni sizning yordamingizsiz bajarishi mumkin."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"mashina usulini yoqish"</string>
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Sozlash"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Chiqarish"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"O‘rganish"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Hech qanday mos faoliyat topilmadi."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Media chiqishni yo‘naltirish"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ilovaga media chiqish ovozini boshqa tashqi qurilmalarga yo‘naltirish uchun ruxsat beradi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d84f2fe..a1509af 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Cho phép ứng dụng nhận và xử lý tin nhắn WAP. Quyền này bao gồm khả năng giám sát hoặc xóa tin nhắn được gửi cho bạn mà không hiển thị chúng cho bạn."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"truy xuất các ứng dụng đang chạy"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Cho phép ứng dụng truy xuất thông tin về các công việc đã và đang chạy gần đây. Việc này có thể cho phép ứng dụng phát hiện thông tin về những ứng dụng nào đã được sử dụng trên thiết bị."</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"Quản lý chủ sở hữu thiết bị và hồ sơ"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Cho phép ứng dụng đặt chủ sở hữu hồ sơ và chủ sở hữu thiết bị."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"sắp xếp lại những ứng dụng đang chạy"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng có thể thực hiện việc này mà không cần bạn nhập."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"bật chế độ trên ô tô"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Thiết lập"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Tháo"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Khám phá"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Không tìm thấy hoạt động nào phù hợp."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Định tuyến thiết bị ra phương tiện"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Cho phép ứng dụng định tuyến thiết bị ra phương tiện đến các thiết bị bên ngoài khác."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 3e17ef4..bbe3287 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"允许该应用接收和处理 WAP 消息。此权限包括监视发送给您的消息或删除发送给您的消息而不向您显示的功能。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"检索正在运行的应用"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允许该应用检索近期运行的和当前正在运行的任务的相关信息。此权限可让该应用了解设备上使用了哪些应用。"</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"管理个人资料和设备所有者"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"允许应用设置个人资料所有者和设备所有者。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"对正在运行的应用重新排序"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"允许该应用将任务移动到前台和后台。该应用可能不经您的命令自行执行此操作。"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"启用车载模式"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"设置"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"弹出"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"浏览"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"未找到匹配的活动。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"更改媒体输出线路"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允许该应用将媒体输出线路更改到其他外部设备。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 865baa3..a698848 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"允許應用程式接收和處理 WAP 訊息。這項權限也能讓應用程式監控訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取有關目前和最近執行的工作的資訊。如此一來,應用程式或可找出裝置上所使用應用程式的相關資訊。"</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"管理您的設定檔和裝置擁有者"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"允許應用程式設定檔案擁有者和裝置擁有者。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"為執行中的應用程式重新排序"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"允許應用程式將工作移至前景或背景。應用程式可以自行處理,您無須操作。"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"啟用行車模式"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"設定"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"移除"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"探索"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"找不到相符的活動。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"轉送媒體輸出"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允許應用程式將媒體輸出轉送至其他外部裝置。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f61d42e..009117a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -274,10 +274,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"允許應用程式接收和處理 WAP 訊息。這項權限也能讓應用程式監控訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取最近執行工作的資訊。這項設定可讓應用程式找出裝置所用程式的相關資訊。"</string>
-    <!-- no translation found for permlab_manageProfileAndDeviceOwners (5979288447973722097) -->
-    <skip />
-    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
-    <skip />
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"管理個人資料和裝置擁有者"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"允許應用程式設定個人資料擁有者和裝置擁有者。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"重新排序正在執行的應用程式"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"允許應用程式將工作移至前景或背景。應用程式可以自行處理,不待您操作。"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"啟用行車模式"</string>
@@ -1080,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"設定"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"退出"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"探索"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"找不到相符的活動。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"轉送媒體輸出"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允許應用程式將媒體輸出轉送至其他外部裝置。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8c2ec6e..a719e07 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1078,6 +1078,22 @@
     <string name="ext_media_init_action" msgid="8317198948634872507">"Ukusetha"</string>
     <string name="ext_media_unmount_action" msgid="1121883233103278199">"Khipha"</string>
     <string name="ext_media_browse_action" msgid="8322172381028546087">"Hlola"</string>
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
     <string name="activity_list_empty" msgid="1675388330786841066">"Ayikho imisebenzi efanayo etholakele"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Yenza umzila wemidiya wokukhiphayo"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ivumela uhlelo lokusebenza ukwenza umzila wokukhiphayo wemidiya kuya kumadivayisi angaphandle."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 887b0a5..52b31b2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1971,7 +1971,7 @@
              {@link android.R.attr#windowTranslucentStatus}.
              Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_STATUS_BAR} on
              the decor view. -->
-        <attr name="windowHasLightStatusBar" format="boolean" />
+        <attr name="windowLightStatusBar" format="boolean" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2329,6 +2329,9 @@
         <!-- Defines whether this view reacts to long click events. -->
         <attr name="longClickable" format="boolean" />
 
+        <!--  Defines whether this view reacts to stylus button press events. -->
+        <attr name="stylusButtonPressable" format="boolean" />
+
         <!-- If false, no state will be saved for this view when it is being
              frozen. The default is true, allowing the view to be saved
              (however it also must have an ID assigned to it for its
@@ -2722,12 +2725,11 @@
         <attr name="value" />
     </declare-styleable>
 
-    <!-- Attributes that can be assigned to an &lt;include&gt; tag. -->
+    <!-- Attributes that can be assigned to an &lt;include&gt; tag.
+         @hide -->
     <declare-styleable name="Include">
         <attr name="id" />
         <attr name="visibility" />
-        <attr name="layout_width" />
-        <attr name="layout_height" />
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -3076,6 +3078,8 @@
             <flag name="typeTouchInteractionEnd" value="0x00200000" />
             <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED} events. -->
             <flag name="typeWindowsChanged" value="0x00400000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_STYLUS_BUTTON_PRESSED} events. -->
+            <flag name="typeStylusButtonPressed" value="0x00800000" />
             <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPES_ALL_MASK} i.e. all events. -->
             <flag name="typeAllMask" value="0xffffffff" />
         </attr>
@@ -7430,6 +7434,10 @@
         <attr name="maxWidth" />
         <!-- An optional query hint string to be displayed in the empty query field. -->
         <attr name="queryHint" format="string" />
+        <!-- Default query hint used when {@code queryHint} is undefined and
+             the search view's {@code SearchableInfo} does not provide a hint.
+             @hide -->
+        <attr name="defaultQueryHint" format="string" />
         <!-- The IME options to set on the query text field. -->
         <attr name="imeOptions" />
         <!-- The input type to set on the query text field. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0c685e0..4631427 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1044,7 +1044,8 @@
 
          <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
          resizeable activities as the system doesn't support fixed orientation on a resizeable
-         activity. -->
+         activity.
+         @hide -->
     <attr name="resizeableActivity" format="boolean" />
 
     <!-- This value indicates how tasks rooted at this activity will behave in lockTask mode.
@@ -1796,6 +1797,7 @@
         <attr name="autoRemoveFromRecents" />
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
+        <!-- @hide -->
         <attr name="resizeableActivity" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index f1d2242..b9825c5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -174,8 +174,4 @@
     <color name="Pink_800">#ffad1457</color>
     <color name="Red_700">#ffc53929</color>
     <color name="Red_800">#ffb93221</color>
-
-    <!-- Floating toolbar colors -->
-    <color name="floating_toolbar_text_color">#DD000000</color>
-    <color name="floating_toolbar_background_color">#FAFAFA</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 56eab2c..0b8b280 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -771,6 +771,14 @@
         <item>10</item>
     </integer-array>
 
+    <!-- Vibrator pattern for feedback about a stylus button press -->
+    <integer-array name="config_stylusButtonPressVibePattern">
+        <item>0</item>
+        <item>1</item>
+        <item>20</item>
+        <item>21</item>
+    </integer-array>
+
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
     <!-- Display low battery warning when battery level dips to this value.
@@ -2054,6 +2062,7 @@
     <string-array translatable="false" name="config_system_condition_providers">
         <item>countdown</item>
         <item>schedule</item>
+        <item>event</item>
     </string-array>
 
     <!-- Priority repeat caller threshold, in minutes -->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bdc8d9f..4b8bd0f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -100,4 +100,7 @@
 
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SCROLL_TO_POSITION}. -->
   <item type="id" name="accessibilityActionScrollToPosition" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_STYLUS_BUTTON_PRESS}. -->
+  <item type="id" name="accessibilityActionStylusButtonPress" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7920949..cf21a1c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2610,10 +2610,9 @@
 
   <public type="attr" name="trackTint" />
   <public type="attr" name="trackTintMode" />
-  <public type="attr" name="resizeableActivity" />
   <public type="attr" name="start" />
   <public type="attr" name="end" />
-  <public type="attr" name="windowHasLightStatusBar" />
+  <public type="attr" name="windowLightStatusBar" />
   <public type="attr" name="numbersInnerTextColor" />
   <public type="attr" name="iconTint" />
   <public type="attr" name="iconTintMode" />
@@ -2653,6 +2652,7 @@
   <public type="id" name="accessibilityActionShowOnScreen" />
   <public type="id" name="accessibilityActionScrollToPosition" />
   <public type="id" name="shareText" />
+  <public type="id" name="accessibilityActionStylusButtonPress" />
 
   <public type="attr" name="allowUndo" />
   <public type="attr" name="colorBackgroundFloating" />
@@ -2679,4 +2679,5 @@
   <public type="attr" name="dynamicResources" />
 
   <public type="attr" name="assistBlocked" />
+  <public type="attr" name="stylusButtonPressable" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 51c2062..f36d448 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3012,6 +3012,26 @@
     <!-- Notification action to browse external media [CHAR LIMIT=20] -->
     <string name="ext_media_browse_action">Explore</string>
 
+    <!-- Notification title when external media is missing [CHAR LIMIT=30] -->
+    <string name="ext_media_missing_title"><xliff:g id="name" example="SD card">%s</xliff:g> missing</string>
+    <!-- Notification body when external media is missing [CHAR LIMIT=30] -->
+    <string name="ext_media_missing_message">Reinsert this device</string>
+
+    <!-- Notification title when moving an application to external storage [CHAR LIMIT=30] -->
+    <string name="ext_media_move_specific_title">Moving <xliff:g id="name" example="Calculator">%s</xliff:g></string>
+    <!-- Notification title when moving data to external storage [CHAR LIMIT=32] -->
+    <string name="ext_media_move_title">Moving data</string>
+
+    <!-- Notification title when moving data to external storage [CHAR LIMIT=32] -->
+    <string name="ext_media_move_success_title">Move complete</string>
+    <!-- Notification title when moving data to external storage [CHAR LIMIT=64] -->
+    <string name="ext_media_move_success_message">Data moved to <xliff:g id="name" example="SD card">%s</xliff:g></string>
+
+    <!-- Notification title when moving data to external storage failed [CHAR LIMIT=32] -->
+    <string name="ext_media_move_failure_title">Couldn\'t move data</string>
+    <!-- Notification title when moving data to external storage failed [CHAR LIMIT=64] -->
+    <string name="ext_media_move_failure_message">Data left at original location</string>
+
     <!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
     <string name="activity_list_empty">No matching activities found.</string>
 
@@ -3993,9 +4013,11 @@
     <!-- Lock-to-app unlock password string -->
     <string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
 
-    <!-- Notification shown when device owner silently installs a package -->
+    <!-- Notification shown when device owner silently installs a package [CHAR LIMIT=NONE] -->
     <string name="package_installed_device_owner">Installed by your administrator</string>
-    <!-- Notification shown when device owner silently deletes a package -->
+    <!-- Notification shown when device owner silently updates a package [CHAR LIMIT=NONE] -->
+    <string name="package_updated_device_owner">Updated by your administrator</string>
+    <!-- Notification shown when device owner silently deletes a package [CHAR LIMIT=NONE] -->
     <string name="package_deleted_device_owner">Deleted by your administrator</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index f81ee8c..c2371ee 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -533,7 +533,7 @@
         <item name="queryBackground">@empty</item>
         <item name="submitBackground">@empty</item>
         <item name="searchHintIcon">@empty</item>
-        <item name="queryHint">@string/search_hint</item>
+        <item name="defaultQueryHint">@string/search_hint</item>
     </style>
 
     <style name="Widget.Material.SegmentedButton" parent="SegmentedButton">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b05fe07..50d2f80 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -698,6 +698,7 @@
   <java-symbol type="string" name="lock_to_app_unlock_pattern" />
   <java-symbol type="string" name="lock_to_app_unlock_password" />
   <java-symbol type="string" name="package_installed_device_owner" />
+  <java-symbol type="string" name="package_updated_device_owner" />
   <java-symbol type="string" name="package_deleted_device_owner" />
   <java-symbol type="string" name="lockscreen_access_pattern_cell_added" />
   <java-symbol type="string" name="lockscreen_access_pattern_cleared" />
@@ -1441,6 +1442,7 @@
   <java-symbol type="array" name="config_longPressVibePattern" />
   <java-symbol type="array" name="config_safeModeDisabledVibePattern" />
   <java-symbol type="array" name="config_safeModeEnabledVibePattern" />
+  <java-symbol type="array" name="config_stylusButtonPressVibePattern" />
   <java-symbol type="array" name="config_virtualKeyVibePattern" />
   <java-symbol type="attr" name="actionModePopupWindowStyle" />
   <java-symbol type="attr" name="dialogCustomTitleDecorLayout" />
@@ -1899,6 +1901,14 @@
   <java-symbol type="string" name="ext_media_init_action" />
   <java-symbol type="string" name="ext_media_unmount_action" />
   <java-symbol type="string" name="ext_media_browse_action" />
+  <java-symbol type="string" name="ext_media_missing_title" />
+  <java-symbol type="string" name="ext_media_missing_message" />
+  <java-symbol type="string" name="ext_media_move_specific_title" />
+  <java-symbol type="string" name="ext_media_move_title" />
+  <java-symbol type="string" name="ext_media_move_success_title" />
+  <java-symbol type="string" name="ext_media_move_success_message" />
+  <java-symbol type="string" name="ext_media_move_failure_title" />
+  <java-symbol type="string" name="ext_media_move_failure_message" />
   <java-symbol type="string" name="usb_storage_error_message" />
   <java-symbol type="string" name="usb_storage_message" />
   <java-symbol type="string" name="usb_storage_notification_message" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index b0f673c..e679e0a 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -56,11 +56,11 @@
 
         <item name="textColorPrimary">@color/primary_text_material_dark</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
-        <item name="textColorPrimaryActivated">@color/primary_text_activated_material_dark</item>
+        <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_dark</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
-        <item name="textColorSecondaryActivated">@color/secondary_text_activated_material_dark</item>
+        <item name="textColorSecondaryActivated">@color/secondary_text_inverse_when_activated_material</item>
         <item name="textColorTertiary">@color/secondary_text_material_dark</item>
         <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
         <item name="textColorHint">@color/hint_foreground_material_dark</item>
@@ -410,10 +410,10 @@
 
         <item name="textColorPrimary">@color/primary_text_material_light</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
-        <item name="textColorPrimaryActivated">@color/primary_text_activated_material_light</item>
+        <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
-        <item name="textColorSecondaryActivated">@color/secondary_text_activated_material_light</item>
+        <item name="textColorSecondaryActivated">@color/secondary_text_inverse_when_activated_material</item>
         <item name="textColorTertiary">@color/secondary_text_material_light</item>
         <item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
@@ -760,7 +760,7 @@
          status bar contents. -->
     <style name="Theme.Material.Light.LightStatusBar">
         <item name="colorPrimaryDark">@color/primary_dark_material_light_light_status_bar</item>
-        <item name="windowHasLightStatusBar">true</item>
+        <item name="windowLightStatusBar">true</item>
     </style>
 
     <style name="ThemeOverlay" />
@@ -777,10 +777,8 @@
 
         <item name="textColorPrimary">@color/primary_text_material_light</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
-        <item name="textColorPrimaryActivated">@color/primary_text_activated_material_light</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
-        <item name="textColorSecondaryActivated">@color/secondary_text_activated_material_light</item>
         <item name="textColorTertiary">@color/secondary_text_material_light</item>
         <item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
@@ -814,11 +812,9 @@
 
         <item name="textColorPrimary">@color/primary_text_material_dark</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
-        <item name="textColorPrimaryActivated">@color/primary_text_activated_material_dark</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_dark</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
-        <item name="textColorSecondaryActivated">@color/secondary_text_activated_material_dark</item>
         <item name="textColorTertiary">@color/secondary_text_material_dark</item>
         <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
         <item name="textColorHint">@color/hint_foreground_material_dark</item>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index e04c214..4b82c3d 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -184,10 +184,10 @@
         result.putInt("ap-discovered", ssidAppearInScanResultsCount);
         getInstrumentation().sendStatus(Activity.RESULT_FIRST_USER, result);
         if (i == mScanIterations + 1) {
-            writeOutput(String.format("iteration %d out of %d", i, mScanIterations));
+            writeOutput(String.format("iteration %d out of %d", i - 1, mScanIterations));
             writeOutput(String.format("average scanning time is %d", scanTimeSum / (i - 1)));
             writeOutput(String.format("ssid appear %d out of %d scan iterations",
-                    ssidAppearInScanResultsCount, i));
+                    ssidAppearInScanResultsCount, i - 1));
         }
     }
 
@@ -289,7 +289,7 @@
         getInstrumentation().sendStatus(Activity.RESULT_FIRST_USER, result);
         if (i == mReconnectIterations + 1) {
             writeOutput(String.format("iteration %d out of %d",
-                    i, mReconnectIterations));
+                    i - 1, mReconnectIterations));
         }
     }
 }
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index a0b26f3..1ea459f 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -50,7 +50,7 @@
 # Do not include Motoya on space-constrained devices
 ifneq ($(SMALLER_FONT_FOOTPRINT),true)
 # Do not include Motoya if we are including full NotoSans
-ifneq ($(FONT_NOTOSANS_FULL),true)
+ifneq ($(FONT_NOTOSANS_JP_FULL),true)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := MTLmr3m.ttf
@@ -61,7 +61,7 @@
 include $(BUILD_PREBUILT)
 extra_font_files += MTLmr3m.ttf
 
-endif  # !FONT_NOTOSANS_FULL
+endif  # !FONT_NOTOSANS_JP_FULL
 endif  # !SMALLER_FONT_FOOTPRINT
 
 ################################
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index dc364a12..0aa588b 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -402,12 +402,12 @@
     </family>
     <family>
         <fileset>
-            <file lang="zh-Hans">NotoSansHans-Regular.otf</file>
+            <file lang="zh-Hans">NotoSansSC-Regular.otf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file lang="zh-Hant">NotoSansHant-Regular.otf</file>
+            <file lang="zh-Hant">NotoSansTC-Regular.otf</file>
         </fileset>
     </family>
     <family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 44ea1c9..f903aab 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -329,10 +329,10 @@
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family lang="zh-Hans">
-        <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
+        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
     </family>
     <family lang="zh-Hant">
-        <font weight="400" style="normal">NotoSansHant-Regular.otf</font>
+        <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
     </family>
     <family lang="ja">
         <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
new file mode 100644
index 0000000..3c63b11
--- /dev/null
+++ b/docs/html-intl/intl/es/index.jd
@@ -0,0 +1,93 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=El sitio oficial para los desarrolladores de Android. Proporciona el SDK de Android y la documentación para los diseñadores y desarrolladores de aplicaciones.
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
+            <p>La actualización 5.0 de Android agrega una variedad de nuevas características para sus aplicaciones, como notificaciones en la pantalla de bloqueo, una nueva API de cámara, OpenGL ES 3.1, una nueva interfaz llamada "Material design", y mucho más.</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">Más información</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">Obtener el SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">Examinar muestras</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">Mirar videos</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">Administrar tus aplicaciones</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">Creado para un mundo de múltiples pantallas</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android se ejecuta en cientos de millones de dispositivos de todo el mundo, <br>
+          y ahora es compatible con estos innovadores factores de forma.
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                Proporciona información dinámica para tus usuarios, cuando la necesiten.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">Obtener información sobre Android Wear</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                Crea aplicaciones para televisores y dale vida a tus contenidos.
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">Obtener información sobre Android TV</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                Extiende tus aplicaciones de música para los sistemas de entretenimiento para automóviles.
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">Más información sobre Android Auto</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
new file mode 100644
index 0000000..e0153fa
--- /dev/null
+++ b/docs/html-intl/intl/ja/index.jd
@@ -0,0 +1,93 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=Android デベロッパー向け公式サイトアプリのデベロッパーおよびデザイナー向け Android SDK とドキュメンテーションを提供します。
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
+            <p>Android 5.0 アップデートでは、ロック画面での通知、新しいカメラ API、OpenGL ES 3.1、新たなマテリアル デザイン インターフェースなど、ご使用のアプリにさまざまな新しい機能を提供します。</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">詳細を見る</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">SDK を入手する</a></div>
+      <div><a href="{@docRoot}samples/index.html">サンプルを見る</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">ビデオを見る</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">アプリを管理する</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">マルチ スクリーンの世界を<br>構築しましょう</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android は世界中の数多くの携帯型デバイスで使われています。 <br>
+          そして今回、これらの新しいフォーム ファクタをサポートします。
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                いつでもどこでも、アプリのユーザーに必要な情報を提供します。
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">Android Wear の詳細を見る</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                大画面向けアプリを作成して、コンテンツを生き生きと表現します。
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">Android TV の詳細を見る</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                音楽アプリを車載エンターテイメント システムに対応させます。
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">Android Auto の詳細を見る</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
new file mode 100644
index 0000000..59b9321
--- /dev/null
+++ b/docs/html-intl/intl/ko/index.jd
@@ -0,0 +1,93 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=Android 개발자 공식 사이트 앱 개발자 및 디자이너에게 Android SDK 및 문서를 제공합니다.
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
+            <p>Android 5.0 업데이트는 사용자 앱에 잠금화면상의 알림, 완전히 새로운 카메라 API, OpenGL ES 3.1, 신규 머티리얼 디자인(Material Design) 인터페이스 등 다양하고 새로운 기능을 추가합니다.</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">자세히 알아보기</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">SDK 받기</a></div>
+      <div><a href="{@docRoot}samples/index.html">샘플 둘러보기</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">비디오 시청</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">앱 관리</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">멀티스크린 월드에 맞게 만들기</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android는 전 세계 수억 개의 휴대 기기에서 구동되고 있으며, <br>
+          이제 이 흥미진진하고 새로운 폼팩터를 지원합니다.
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                사용자가 필요로 할 때 언제든지 실시간으로 정보를 제공합니다.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">Android Wear에 대해 알아보세요</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                대형 스크린에 적합한 앱과 컨텐츠를 구성하세요.
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">Android TV에 대해 알아보세요</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                음악 앱을 자동차 엔터테인먼트 시스템에 적용해보세요.
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">Android Auto에 대해 알아보세요</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
new file mode 100644
index 0000000..bf6c57d
--- /dev/null
+++ b/docs/html-intl/intl/pt-br/index.jd
@@ -0,0 +1,93 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=O site oficial dos desenvolvedores Android. Fornece o Android SDK e a documentação para desenvolvedores e projetistas de aplicativos.
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" /> 
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
+            <p>A atualização do Android 5.0 adiciona diversos novos recursos aos aplicativos, como notificações na tela de bloqueio, uma API de câmera totalmente nova, OpenGL ES 3.1, a nova interface do Material Design e muito mais.</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">Saiba mais</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">Obtenha o SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">Procure amostras</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">Assista a vídeos</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">Gerencie seus aplicativos</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">Crie para um mundo multitela</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          O Android funciona em milhões de dispositivos portáteis em todo o mundo <br>
+          e agora é compatível com esses novos e empolgantes recursos.
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"><img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                Forneça informações constantemente aos usuários, sempre que precisarem.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">Conheça o Android Wear</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                Crie aplicativos para a telona e dê vida ao conteúdo.
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">Conheça o Android TV</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                Estenda seus aplicativos de música a sistema de entretenimento de automóveis.
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">Conheça o Android Auto</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
new file mode 100644
index 0000000..eb7ffe4
--- /dev/null
+++ b/docs/html-intl/intl/ru/index.jd
@@ -0,0 +1,93 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=Официальный сайт для разработчиков Android. На этом сайте вы найдете пакеты Android SDK и документацию для дизайнеров и разработчиков приложений.
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
+            <p>Обновление Android 5.0 содержит различные новые возможности для приложений: уведомления на заблокированном экране, совершено новый API камеры, OpenGL ES 3.1, новый интерфейс Material Design и множество других функций.</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">Подробнее</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">Пакет SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">Примеры</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">Видеоролики</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">Управление приложениями</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">ОС для многоэкранных устройств</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Сотни миллионов мобильных устройств по всему миру работают под управлением операционной системы Android. <br>
+          А теперь эта система радует и обладателей устройств других форм-факторов.
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                Предоставляйте пользователям информацию прямо на ходу, когда бы им это ни потребовалось.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">Подробнее об Android Wear</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                Создавайте приложения для использования на большом экране телевизора и разрабатывайте динамичный контент.
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">Подробнее об Android TV</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                Автомобильные мультимедийные системы — прекрасная возможность расширить список поддерживаемых устройств для музыкальных приложений.
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">Подробнее об Android Auto</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
index 590332f..1c2fb99 100644
--- a/docs/html-intl/intl/zh-cn/index.jd
+++ b/docs/html-intl/intl/zh-cn/index.jd
@@ -1,15 +1,11 @@
 fullpage=true
 page.viewport_width=970
 excludeFromSuggestions=true
-page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
+page.metaDescription=Android 开发人员的官方网站。为应用开发人员以及设计师提供 Android SDK 和文档。
 page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
 
 @jd:body
 
-
-
-
-
 <div class="home-new-carousel-1">
   <div class="fullscreen-carousel-content">
     <div class="vcenter">
@@ -19,38 +15,31 @@
           <div class="resource resource-card resource-card-18x6">
 
       <div class="landing-section-header">
-            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png"
-                 srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x"
-                 width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
             <div class="col-5" style=" margin-top:70px ">
             <h3 stye="font-weight:300;">Android 5.0 Lollipop</h3>
-            <p>在 Android 5.0 的版本更新中,我们添加了多种可用于你的应用程序的新功能,比如锁屏通知,一个全新的相机API,OpenGL ES 3.1,以及新的 Material Design 界面等等。</p>
+            <p>Android 5.0 更新将为您的应用增添各种新功能,例如锁定屏幕通知、全新的相机 API、OpenGL ES 3.1、全新的 Material Design 界面等等。</p>
             <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">了解详情</a>
             </div>
           </div>
           </div>
         </div>
        <h2>&nbsp;</h2>
-        
-        <div style="margin-top:20px" class="resource-widget resource-flow-layout wrap col-16
-        no-section" data-query="collection:index/primary/zhcn" data-resourcestyle="card"
-        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> 
-
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
       </div> <!-- end .wrap -->
     </div> <!-- end .vcenter -->
   </div> <!-- end .fullscreen-carousel-content -->
 </div> <!-- end .fullscreen-carousel -->
 
-
-
-
 <div class="actions-bar" style="margin-top:20px">
   <div class="wrap">
     <div class="actions">
-      <div><a href="/sdk/index.html">下载 SDK</a></div>
-      <div><a href="/samples/index.html">浏览示例</a></div>
+      <div><a href="{@docRoot}sdk/index.html">获得 SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">浏览示例</a></div>
       <div><a href="//www.youtube.com/user/androiddevelopers">观看视频</a></div>
-      <div><a href="/distribute/googleplay/developer-console.html">管理应用</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">管理您的应用</a></div>
     </div><!-- end .actions -->
   </div><!-- end .wrap -->
 </div><!-- end .actions-bar -->
@@ -61,44 +50,41 @@
   <div class="landing-section">
     <div class="wrap">
       <div class="landing-section-header">
-        
-            <div class="landing-h1" style="margin-top:0px">专为跨屏世界打造</div>
-        <div class="landing-subhead" style="margin-top:20px">
-          全球数亿手持设备安装的都是 Android 系统。<br />
-          现在 Android 系统还支持以下这些备受期待的新设备。
+
+            <div class="landing-h1" style="margin-top:0px">专为多屏幕时代而设</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android 在全球各地的数亿台手持设备上运行, <br>
+          如今更支持下列激动人心的新设备和配置。
         </div>
       </div>
-      <div class="landing-body" style="margin-top:50px">
+      <div class="landing-body" style="margin-top: 50px;">
         <div class="landing-breakout cols">
           <div class="col-3-wide">
-              <img src="{@docRoot}images/home/wear-wordmark.png" />
-              <img src="{@docRoot}images/home/wear.png" />
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
               <p class="landing-small">
-                让用户随时随地获得需要的信息。
+                让您的用户即便在途中亦能随时随地获得所需的信息。
             </p>
             <p class="landing-small">
-              <a href="/wear/index.html">了解 Android Wear</a>
+              <a href="{@docRoot}wear/index.html">了解关于 Android Wear 的信息</a>
             </p>
           </div>
           <div class="col-3-wide">
-              <img src="{@docRoot}images/home/tv-wordmark.png" />
-             <img src="{@docRoot}images/home/tv.png" />
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
               <p class="landing-small">
-                针对大屏幕打造应用,使你的内容引人入胜。
+                将您的应用搬上大屏幕,使您的内容栩栩如生。
               </p>
             <p class="landing-small">
-              <a href="/tv/index.html">了解 Android TV</a>
+              <a href="{@docRoot}tv/index.html">了解关于 Android TV 的信息</a>
 
             </p>
           </div>
           <div class="col-3-wide">
-              <img src="{@docRoot}images/home/auto-wordmark.png" />
-              <img src="{@docRoot}images/home/auto.png" />
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
               <p class="landing-small">
-                将你的音乐应用扩展到车载娱乐系统。
+                将您的音乐应用扩展至车载娱乐系统。
              </p>
             <p class="landing-small">
-              <a href="/auto/index.html">了解 Android Auto</a>
+              <a href="{@docRoot}auto/index.html">了解关于 Android Auto 的信息</a>
             </p>
           </div>
         </div>
diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
new file mode 100644
index 0000000..56ae4cf
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/index.jd
@@ -0,0 +1,92 @@
+fullpage=true
+page.viewport_width=970excludeFromSuggestions=true
+page.metaDescription=適用於 Android 開發人員的官方網站。提供適用於應用程式開發人員與設計師的 Android SDK 與文件。
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" /> 
+
+@jd:body
+
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+
+      <div class="landing-section-header">
+            <div class="col-10"><img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="510" style="margin:20px 30px 0 30px"></div>
+            <div class="col-5" style=" margin-top:70px ">
+            <h3 stye="font-weight:300;">Android 5.0 棒棒糖</h3>
+            <p>Android 5.0 更新新增了許多新功能到您的應用程式,例如鎖定螢幕上的通知、全新的相機 API、OpenGL ES 3.1、新的材料設計介面,還有更多其他功能。</p>
+            <a href="{@docRoot}about/versions/lollipop.html" class="landing-button landing-primary">深入了解</a>
+            </div>
+          </div>
+          </div>
+        </div>
+       <h2>&nbsp;</h2>
+        <div style="margin-top:20px;height:115px" class="resource-widget resource-flow-layout wrap col-16
+        no-section" data-query="collection:index/primary" data-resourcestyle="card"
+        data-sortorder="-timestamp" data-maxresults="3" data-cardsizes="6x2,6x2,6x2"></div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
+
+<div class="actions-bar" style="margin-top:20px">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">取得 SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">瀏覽範例</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">觀賞影片</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">管理您的應用程式</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
+
+
+
+<div class="landing-rest-of-page">
+  <div class="landing-section">
+    <div class="wrap">
+      <div class="landing-section-header">
+
+            <div class="landing-h1" style="margin-top:0px">針對多螢幕世界建置</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android 在全球數百萬部手持式裝置上執行, <br>
+          而且它現在支援這些令人興奮、各種尺寸的裝置。
+        </div>
+      </div>
+      <div class="landing-body" style="margin-top: 50px;">
+        <div class="landing-breakout cols">
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/wear-wordmark.png"> <img src="{@docRoot}images/home/wear.png">
+              <p class="landing-small">
+                為您的使用者提供可隨時隨地存取的資訊。
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear/index.html">了解 Android Wear</a>
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/tv-wordmark.png"> <img src="{@docRoot}images/home/tv.png">
+              <p class="landing-small">
+                為大螢幕建置您的應用程式,並將您的內容帶到生活中。
+              </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv/index.html">了解 Android TV</a>
+
+            </p>
+          </div>
+          <div class="col-3-wide">
+              <img src="{@docRoot}images/home/auto-wordmark.png"> <img src="{@docRoot}images/home/auto.png">
+              <p class="landing-small">
+                將您的音樂應用程式延伸到車用娛樂系統。
+             </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto/index.html">了解 Android Auto</a>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
index a12e753..cf83a5e 100644
--- a/docs/html/distribute/tools/promote/brand.jd
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -37,6 +37,18 @@
       <p>If used with your logo, "for Android" should be no larger than 90% of your logo’s size.
       First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
     </li>
+    <li>"Android TV", "Android Wear" and "Android Auto" may only be used to identify or market
+      products or services with prior approval.  Use "for Android" or "with Android" for all
+      other Android-based products
+      <ul>
+        <li><span style="color:red">Incorrect</span>: "Android TV Streaming Stick",
+          "Streaming Stick with Android TV"</li>
+        <li><span style="color:green">Correct</span>: "Streaming Stick with Android"</li>
+      </ul>
+      <p>If used with your logo, "for Android" or "with Android" should be no larger than 90% of
+        your logo’s size. First instance of this use should be followed by a TM symbol,
+        "for Android&trade;".</p>
+    </li>
     <li>Android may be used as a descriptor, as long as it is followed by a
         proper generic term. (Think of "Android" as a term used in place of
         "the Android platform.")
diff --git a/docs/html/guide/components/processes-and-threads.jd b/docs/html/guide/components/processes-and-threads.jd
index e7ef7ba..10a6410 100644
--- a/docs/html/guide/components/processes-and-threads.jd
+++ b/docs/html/guide/components/processes-and-threads.jd
@@ -274,7 +274,8 @@
 public void onClick(View v) {
     new Thread(new Runnable() {
         public void run() {
-            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
+            final Bitmap bitmap =
+                    loadImageFromNetwork("http://example.com/image.png");
             mImageView.post(new Runnable() {
                 public void run() {
                     mImageView.setImageBitmap(bitmap);
@@ -323,7 +324,7 @@
     protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
     }
-    
+
     /** The system calls this to perform work in the UI thread and delivers
       * the result from doInBackground() */
     protected void onPostExecute(Bitmap result) {
diff --git a/docs/html/images/tools/studio-add-icon.png b/docs/html/images/tools/studio-add-icon.png
new file mode 100644
index 0000000..3ff49f6
--- /dev/null
+++ b/docs/html/images/tools/studio-add-icon.png
Binary files differ
diff --git a/docs/html/images/tools/studio-debug-settings-icon.png b/docs/html/images/tools/studio-debug-settings-icon.png
new file mode 100644
index 0000000..ee9c7a1
--- /dev/null
+++ b/docs/html/images/tools/studio-debug-settings-icon.png
Binary files differ
diff --git a/docs/html/images/tools/studio-inspections-config.png b/docs/html/images/tools/studio-inspections-config.png
index e41afa1..15a5a5b 100644
--- a/docs/html/images/tools/studio-inspections-config.png
+++ b/docs/html/images/tools/studio-inspections-config.png
Binary files differ
diff --git a/docs/html/images/tools/studio-memory-monitor.png b/docs/html/images/tools/studio-memory-monitor.png
index 796daf0..58147b7 100644
--- a/docs/html/images/tools/studio-memory-monitor.png
+++ b/docs/html/images/tools/studio-memory-monitor.png
Binary files differ
diff --git a/docs/html/images/tools/studio-memory-monitor2x.png b/docs/html/images/tools/studio-memory-monitor2x.png
new file mode 100644
index 0000000..7c3d6c4
--- /dev/null
+++ b/docs/html/images/tools/studio-memory-monitor2x.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 06577720..31d2efb 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,27 +4,29 @@
 header.hide=1
 page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
 
-studio.version=1.1.0
+studio.version=1.2.0
 
-studio.linux_bundle_download=android-studio-ide-135.1740770-linux.zip
-studio.linux_bundle_bytes=259336386
-studio.linux_bundle_checksum=e8d166559c50a484f83ebfec6731cc0e3f259208
+studio.linux_bundle_download=android-studio-ide-141.1890965-linux.zip
+studio.linux_bundle_bytes=259139652 
+studio.linux_bundle_checksum=72149f65911ca18d8f0d360e6b7a1e2dc57e9935
 
-studio.mac_bundle_download=android-studio-ide-135.1740770-mac.dmg
-studio.mac_bundle_bytes=261303345
-studio.mac_bundle_checksum=f9745d0fec1eefd498f6160a2d6a1b5247d4cda3
+studio.mac_bundle_download=android-studio-ide-141.1890965-mac.dmg
+studio.mac_bundle_bytes=260877150
+studio.mac_bundle_checksum=06fe5a2d9ab6c99bf42fb2014e519a073fc7e90d
 
-studio.win_bundle_exe_download=android-studio-bundle-135.1740770-windows.exe
-studio.win_bundle_exe_bytes=856233768
-studio.win_bundle_exe_checksum=7484b9989d2914e1de30995fbaa97a271a514b3f
+studio.win_bundle_download=android-studio-ide-141.1890965-windows.zip
+studio.win_bundle_bytes=261548058
+studio.win_bundle_checksum=29416e54ad074881a1e668e61e3d0c2316108dbe
 
-studio.win_notools_exe_download=android-studio-ide-135.1740770-windows.exe
-studio.win_notools_exe_bytes=242135128
-studio.win_notools_exe_checksum=5ea77661cd2300cea09e8e34f4a2219a0813911f
 
-studio.win_bundle_download=android-studio-ide-135.1740770-windows.zip
-studio.win_bundle_bytes=261667054
-studio.win_bundle_checksum=e903f17cc6a57c7e3d460c4555386e3e65c6b4eb
+studio.win_bundle_exe_download=android-studio-bundle-141.1890965-windows.exe
+studio.win_bundle_exe_bytes=928285584
+studio.win_bundle_exe_checksum=47be67749409f0d710c05b9a8f22d9191c47a9d0
+
+studio.win_notools_exe_download=android-studio-ide-141.1890965-windows.exe
+studio.win_notools_exe_bytes=243621072
+studio.win_notools_exe_checksum=760d45212bea42f52adb1cbeab2390156d49c74d
+
 
 
 
@@ -425,8 +427,7 @@
 
 <p style="margin:0">
 For more details about features available in Android Studio,
-read the guide to <a href="{@docRoot}tools/studio/index.html"
-  >Android Studio Basics</a>.</p>
+read the overview at <a href="{@docRoot}tools/studio/index.html">Android Studio</a>.</p>
 </div>
 
 
diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd
index c3edff6..4e732f0 100644
--- a/docs/html/sdk/installing/studio-tips.jd
+++ b/docs/html/sdk/installing/studio-tips.jd
@@ -22,8 +22,8 @@
      <h2>Smart Rendering</h2>
      <p>With smart rendering, Android Studio displays links for quick fixes to rendering errors.
      For example, if you add a button to the layout without specifying the <em>width</em> and
-     <em>height</em> atttributes, Android Studio displays the rendering message <em>Automatically
-     add all missing attributs</em>. Clicking the message adds the missing attributes to the layout.</p>
+     <em>height</em> attributes, Android Studio displays the rendering message <em>Automatically
+     add all missing attributes</em>. Clicking the message adds the missing attributes to the layout.</p>
 
 
      <h2> Bitmap rendering in the debugger</h2>
@@ -41,7 +41,6 @@
      <p class="img-caption"><strong>Figure 14.</strong> Filter Build Messages</p>
 
 
-
     <h2>Hierarchical parent setting</h2>
     <p>The activity parent can now be set in the Activity Wizard when creating a new
     activity. Setting a <em>hierarchal parent</em> sets the {@code Up} button to automatically
@@ -69,7 +68,47 @@
     with a layout hierarchy and a list of properties for each view in the layout.</p>
 
 
-     <h2 id="intellij">Working with IntelliJ</h3>
+   <h3>Annotations</h3>
+   <p>Android Studio provides coding assistance for using annotations from the
+   {@link android.support.annotation Support-Annotations} library, part of the
+   Support Repository. Adding a dependency for this library enables you to decorate your code with
+   annotations to help catch bugs, such as null pointer exceptions and resource type conflicts.
+   You can also create enumerated annotations to, for example, check that a passed parameter value
+   matches a value from a defined set of constants. For more information, see
+   <a href="{@docRoot}tools/debugging/annotations.html#annotations">Improving Code Inspection with
+   Annotations</a>. </p>
+
+
+   <h3>Java class decompiling</h3>
+   <p>Android Studio allows you to look at what’s inside Java libraries when you don’t have access
+   to the source code. </p>
+
+   <p>The decompiler is built into Android Studio for easy access. To use this feature, right-click
+   a class, method, or field from a library for which you do not have source file access and select
+   <strong>decompile</strong>.</p> The decompiled source code appears. </p>
+
+   <p>To adjust the Java decompiler settings, select
+   <strong>File > Settings > Other Settings > Java Decompiler</strong>. </p>
+
+
+   <h3>Debugging and performance enhancements</h3>
+   <p>Android Studio offers debugging and performance enhancements such as:</p>
+   <ul>
+    <li>Auto detect an expanded set of code styles. To modify the current code style, choose
+      <strong>File &gt; Settings &gt; Code Styles</strong>.  </li>
+    <li>Support for high density (Retina) displays on Windows and Linux.  </li>
+    <li>Scratch files for quick prototyping without creating any project files.
+      <p>Choose <strong>Tools &gt; New Scratch File</strong> to open a scratch file to quickly
+      build and run code prototypes. Together with Android Studio coding assistance, scratch
+      files allow you to quickly run and debug code updates with the support of all file operations.
+      By embedding code created with scripting languages, you can run your code from within the
+      scratch file.</p> 
+    </li>
+  </ul>
+
+
+
+<h2 id="intellij">Working with IntelliJ-based Coding Practices</h2>
 
      <p>This section list just a few of the code editing
      practices you should consider using when creating Android Studio apps. </p>
@@ -78,8 +117,6 @@
      is based), refer to the
      <a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA documentation</a>.</p>
 
-
-
      <h3><em>Alt + Enter</em> key binding</h3>
      <p>For quick fixes to coding errors, the IntelliJ powered IDE implements the <em>Alt + Enter</em>
      key binding to fix errors (missing imports, variable assignments, missing references, etc) when
@@ -108,18 +145,16 @@
     of a string as not null.</p>
 
 
-
     <h3>Injecting languages</h3>
     <p>With language injection, the Android Studio IDE allows you to work with islands of different
     languages embedded in the source code. This extends the syntax, error highlighting and coding
     assistance to the embedded language. This can be especially useful for checking regular expression
-    values inline, and validating XML and SQL statments.</p>
-
+    values inline, and validating XML and SQL statements.</p>
 
     <h3>Code folding</h3>
     <p>This allows you to selectively hide and display sections of the code for readability. For
     example, resource expressions or code for a nested class can be folded or hidden in to one line
-    to make the outer class structure easier to read. The inner clas can be later expanded for
+    to make the outer class structure easier to read. The inner class can be later expanded for
     updates. </p>
 
 
@@ -140,6 +175,7 @@
     resolved values for the various attributes that are pulled in.</p>
 
 
+
      <h3>New Allocation Tracker integration in the Android/DDMS window</h3>
      <p>You can now inspect theme attributes using <strong> View > Quick Documentation
      </strong> <code>F1</code>, see the theme inheritance hierarchy, and resolved values for the
diff --git a/docs/html/tools/building/building-cmdline.jd b/docs/html/tools/building/building-cmdline.jd
index ec00b50..33798a5 100644
--- a/docs/html/tools/building/building-cmdline.jd
+++ b/docs/html/tools/building/building-cmdline.jd
@@ -34,9 +34,9 @@
     </div>
   </div>
 
-  <p>By default, there are two build types to build your application using the gradle.build settings:
+  <p>By default, there are two build types to build your application using the Gradle build settings:
   one for debugging your application &mdash; <em>debug</em> &mdash; and one for building your
-  final package for release &mdash; <em>release mode</em>. Regardless of which way you build type
+  final package for release &mdash; <em>release mode</em>. Regardless of which build type
   your modules use, the app must be signed before it can install on an emulator or device&mdash;with
   a debug key when building in debug mode and with your own private key when building in release mode.</p>
 
@@ -48,23 +48,24 @@
   development device. You cannot distribute an application that is signed with a debug key.
   When you build using the release build type, the .apk file is <em>unsigned</em>, so you
   must manually sign it with your own private key, using Keytool and Jarsigner settings in the
-  module's gradle.build file.</p>
+  module's <code>build.gradle</code> file.</p>
 
   <p>It's important that you read and understand <a href=
   "{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a>, particularly once
   you're ready to release your application and share it with end-users. That document describes the
-  procedure for generating a private key and then using it to sign your .apk file. If you're just
+  procedure for generating a private key and then using it to sign your APK file. If you're just
   getting started, however, you can quickly run your applications on an emulator or your own
   development device by building in debug mode.</p>
 
   <p>If you don't have <a href="http://www.gradle.org/">Gradle</a>, you can obtain it from the <a href="http://gradle.org/">Gradle
-  home page</a>. Install it and make sure it is in your executable PATH. Before calling Ant, you
+  home page</a>. Install it and make sure it is in your executable PATH. Before calling Gradle, you
   need to declare the JAVA_HOME environment variable to specify the path to where the JDK is
   installed.</p>
 
-  <p class="note"><strong>Note:</strong> When installing JDK on Windows, the default is to install
-  in the "Program Files" directory. This location will cause <code>ant</code> to fail, because of
-  the space. To fix the problem, you can specify the JAVA_HOME variable like this:
+  <p class="note"><strong>Note:</strong> When using <code>ant</code> and installing JDK on Windows,
+  the default is to install in the "Program Files" directory. This location will cause
+  <code>ant</code> to fail, because of the space. To fix the problem, you can specify the JAVA_HOME
+  variable like this:
   <pre>set JAVA_HOME=c:\Progra~1\Java\&lt;jdkdir&gt;</pre>
 
   <p>The easiest solution, however, is to install JDK in a non-space directory, for example:</p>
diff --git a/docs/html/tools/debugging/annotations.jd b/docs/html/tools/debugging/annotations.jd
new file mode 100644
index 0000000..fe9f9cc
--- /dev/null
+++ b/docs/html/tools/debugging/annotations.jd
@@ -0,0 +1,241 @@
+page.title=Improving Code Inspection with Annotations
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#adding-nullness">Adding Nullness Annotations</a></li>
+      <li><a href="#res-annotations">Adding Resource Annotation</a></li>
+      <li><a href="#enum-annotations">Creating Enumerated Annotations</a></li>
+    </ol>
+
+  <h2>See also</h2>
+  <ol>
+     <li><a href="{@docRoot}tools/help/lint.html">lint (reference)</a></li>
+     <li><a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a></li>
+     <li><a href="{@docRoot}tools/studio/index.html#annotations">Annotations in Android Studio</a></li>
+  </ol>
+
+</div>
+</div>
+
+<p>Using code inspections tools such as <a href="{@docRoot}tools/help/lint.html">lint</a> can help
+you find problems and improve your code, but inspection tools can only infer so much. Android
+resource ids, for example, use an {@code int} to identify strings, graphics, colors and other
+resource types, so inspection tools cannot tell when you have specified a string resource where
+you should have specified a color. This situation means that your app may render incorrectly or
+fail to run at all, even if you use code inspection. </p>
+
+<p>Annotations allow you to provide hints to code inspections tools like {@code lint}, to help
+detect these, more subtle code problems. They are added as metadata tags that you attach to
+variables, parameters, and return values to inspect method return values, passed parameters, and
+local variables and fields. When used with code inspections tools, annotations can help you detect
+problems, such as null pointer exceptions and resource type
+conflicts. </p>
+
+<p>For more information on enabling <a href="{@docRoot}tools/help/lint.html">lint</a> inspections
+and running <a href="{@docRoot}tools/help/lint.html">lint</a>,
+see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+
+<p>Android supports a variety of annotations for insertion in the methods, parameters, and return
+values in your code, for example:</p>
+
+<dl>
+    <dt>{@link android.support.annotation.Nullable @Nullable}</dt>
+    <dd>Can be null.</dd>
+
+    <dt>{@link android.support.annotation.NonNull @NonNull}</dt>
+    <dd>Cannot be null.</dd>
+
+    <dt>{@link android.support.annotation.StringRes @StringRes}</dt>
+    <dd>References a <a href="{@docRoot}reference/android/R.string.html"><code>R.string</code></a>
+    resource.</dd>
+
+    <dt>{@link android.support.annotation.DrawableRes @DrawableRes}</dt>
+    <dd>References a
+    <a href="{@docRoot}guide/topics/resources/drawable-resource.html"><code>Drawable</code></a>
+    resource. </dd>
+
+    <dt>{@link android.support.annotation.ColorRes @ColorRes}</dt>
+    <dd>References a <a href="{@docRoot}reference/android/graphics/Color.html"><code>Color</code></a>
+    resource. </dd>
+
+    <dt>{@link android.support.annotation.InterpolatorRes @InterpolatorRes}</dt>
+    <dd>References a
+    <a href="{@docRoot}reference/android/view/animation/Interpolator.html"><code>Interpolator</code></a>
+    resource. </dd>
+
+    <dt>{@link android.support.annotation.AnyRes @AnyRes}</dt>
+    <dd>References any type of <a href="{@docRoot}reference/android/R.html"><code>R.</code></a>
+    resource. </dd>
+  </dl>
+
+<p>For a complete list of the supported annotations, either examine the contents of the
+{@link android.support.annotation Support-Annotations} library or use the
+auto-complete feature to display the available options for the <code>import
+android.support.annotation.</code> statement. The
+<a href="{@docRoot}tools/help/sdk-manager.html"> SDK Manager</a> packages the
+{@link android.support.annotation Support-Annotations} library in the Android Support Repository
+for use with Android Studio and in the Android
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> for use with other Android
+development tools.</p>
+
+
+<p>To add annotations to your code, first add a dependency to the
+{@link android.support.annotation Support-Annotations} library. In Android Studio,
+add the dependency to your <code>build.gradle</code> file. </p>
+
+<pre>
+dependencies {
+    compile 'com.android.support:support-annotations:22.0.0'
+}
+</pre>
+
+
+<p>The {@link android.support.annotation Support-Annotations} library is decorated with the
+supported annotations so using this library's methods and resources automatically checks the code
+for potential problems.</p>
+
+<p>If you include annotations in a library and use the
+<a href="{@docRoot}tools/building/plugin-for-gradle.html"><code>Android Plugin for Gradle</code></a>
+to build an Android ARchive (AAR) artifact of that library, the annotations are included as part
+of the artifact in XML format in the <code>annotations.zip</code> file. </p>
+
+<p>To start a code inspection from Android Studio, which includes validating annotations and
+automatic <a href="{@docRoot}tools/help/lint.html">lint</a> checking, select
+<strong>Analyze > Inspect Code</strong> from the menu options. Android Studio displays conflict
+messages throughout the code to indication annotation conflicts and suggest possible
+resolutions.</p>
+
+
+<h2 id="adding-nullness">Adding Nullness Annotations</h2>
+<p>Add {@link android.support.annotation.Nullable @Nullable} and
+{@link android.support.annotation.NonNull @NonNull} annotations to check
+the nullness of a given variable, parameter, or return value. For example, if a local variable
+that contains a null value is passed as a parameter to a method with the
+{@link android.support.annotation.NonNull @NonNull} annotation
+attached to that parameter, building the code generates a warning indicating a non-null conflict. </p>
+
+<p>This example attaches the {@link android.support.annotation.NonNull @NonNull} annotation to
+the <code>context</code> and <code>attrs</code> parameters to check that the passed parameter
+values are not null. </p>
+
+<pre>
+import android.support.annotation.NonNull;
+...
+
+    /** Add support for inflating the &lt;fragment&gt; tag. */
+    &#64;NonNull
+    &#64;Override
+    public View onCreateView(String name, &#64;NonNull Context context,
+      &#64;NonNull AttributeSet attrs) {
+      ...
+      }
+...
+</pre>
+
+<p class="note"><strong>Note:</strong> Android Studio supports running a nullability analysis to
+automatically infer and insert nullness annotations in your code. For more information about
+inferring nullability in Android Studio, see
+<a href="{@docRoot}tools/studio/index.html#annotations">Annotations in Android Studio</a>. </p>
+
+
+<h2 id="res-annotations">Adding Resource Annotations</h2>
+<p>Add {@link android.support.annotation.StringRes @StringRes} annotations to check that
+a resource parameter contains a
+<a href="{@docRoot}reference/android/R.string.html"><code>R.string</code></a>
+reference. During code inspection, the annotation generates a warning if a <code>R.string</code>
+reference is not passed in the parameter.</p>
+
+<p>Validating resource types can be useful as Android references to
+<a href="{@docRoot}guide/topics/resources/drawable-resource.html"><code>Drawables</code></a> and
+<a href="{@docRoot}reference/android/R.string.html"><code>R.string</code></a> resources are both
+passed as integers. Code that expects a parameter to reference a <code>Drawable</code> can be passed
+the expected reference type of int, but actually reference a <code>R.string</code></a> resource. </p>
+
+<p>This example attaches the {@link android.support.annotation.StringRes @StringRes}
+annotation to the <code>resId</code> parameter to validate that it is really a string resource.  </p>
+
+<pre>
+import android.support.annotation.StringRes;
+...
+    public abstract void setTitle(&#64;StringRes int resId);
+    ...
+</pre>
+
+
+<p>Annotations for the other resource types, such as
+{@link android.support.annotation.DrawableRes @DrawableRes},
+{@link android.support.annotation.ColorRes @ColorRes}, and
+{@link android.support.annotation.InterpolatorRes @InterpolatorRes} can be added using
+the same annotation format and run during the code inspection.  </p>
+
+
+<h2 id="enum-annotations">Creating Enumerated Annotations</h2>
+<p>Use the {@link android.support.annotation.IntDef @IntDef} and
+{@link android.support.annotation.StringDef @StringDef} annotations
+so you can create enumerated annotations of integer and string sets to validate other types of code
+references, such as passing references to a set of constants. </p>
+
+<p>The following example illustrates the steps to create an enumerated annotation that ensures
+a value passed as a method parameter references one of the defined constants.</p>
+
+<pre>
+import android.support.annotation.IntDef;
+...
+public abstract class ActionBar {
+    ...
+    //Define the list of accepted constants
+    &#64;IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+
+    //Tell the compiler not to store annotation data in the <code>.class</code> file
+    &#64;Retention(RetentionPolicy.SOURCE)
+
+    //Declare the <code>NavigationMode</code> annotation
+    public &#64;interface NavigationMode {}
+
+    //Declare the constants
+    public static final int NAVIGATION_MODE_STANDARD = 0;
+    public static final int NAVIGATION_MODE_LIST = 1;
+    public static final int NAVIGATION_MODE_TABS = 2;
+
+    //Decorate the target methods with the annotation
+    &#64;NavigationMode
+    public abstract int getNavigationMode();
+
+    //Attach the annotation
+    public abstract void setNavigationMode(&#64;NavigationMode int mode);
+
+</pre>
+
+<p>When you build this code, a warning is generated if the <code>mode</code> parameter does
+not reference one of the defined constants (<code>NAVIGATION_MODE_STANDARD</code>,
+<code>NAVIGATION_MODE_LIST</code>, or <code>NAVIGATION_MODE_TABS</code>).</p>
+
+<p>You can also define an annotation with a <code>flag</code> to check if a parameter
+or return value references a valid pattern. This example creates the
+<code>DisplayOptions</code> annotation with a list of valid <code>DISPLAY_</code> constants. </p>
+
+<pre>
+import android.support.annotation.IntDef;
+...
+
+&#64;IntDef(flag=true, value={
+        DISPLAY_USE_LOGO,
+        DISPLAY_SHOW_HOME,
+        DISPLAY_HOME_AS_UP,
+        DISPLAY_SHOW_TITLE,
+        DISPLAY_SHOW_CUSTOM
+})
+&#64;Retention(RetentionPolicy.SOURCE)
+public &#64;interface DisplayOptions {}
+
+...
+</pre>
+
+<p>When you build code with an annotation flag, a warning is generated if the decorated parameter
+or return value does not reference a valid pattern.</p>
+
+
diff --git a/docs/html/tools/debugging/improving-w-lint.jd b/docs/html/tools/debugging/improving-w-lint.jd
index ff94b7f..8f74f46 100644
--- a/docs/html/tools/debugging/improving-w-lint.jd
+++ b/docs/html/tools/debugging/improving-w-lint.jd
@@ -22,6 +22,7 @@
       <h2>See Also</h2>
           <ol>
               <li><a href="{@docRoot}tools/help/lint.html">lint (reference)</a></li>
+              <li><a href="{@docRoot}tools/degugging/annotations.html">Using Android Annotations</a></li>
           </ol>
     </div>
 </div>
diff --git a/docs/html/tools/revisions/gradle-plugin.jd b/docs/html/tools/revisions/gradle-plugin.jd
index fd294d2..90ec44a 100644
--- a/docs/html/tools/revisions/gradle-plugin.jd
+++ b/docs/html/tools/revisions/gradle-plugin.jd
@@ -36,9 +36,77 @@
 <p>For a summary of known issues in Android Plugin for Gradle, see <a
 href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
 
+
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Plugin for Gradle, Revision 1.2.0</a> <em>(April 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Gradle 2.2.1 or higher.</li>
+        <li>Build Tools 21.1.1 or higher.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+      <li>Enhanced support for running unit tests with Gradle.  </li>
+        <ul>
+          <li>Added support to include Java-style resources in the classpath when running unit
+            tests directly from Gradle.
+          </li>
+          <li>Added unit test dependency support for Android ARchive (AAR) artifacts.
+          </li>
+          <li>Added support for the <code>unitTestVariants</code> property so unit test variants
+            can be manipulated using the <code>build.gradle</code> file.
+          </li>
+          <li>Added the <code>unitTest.all</code> code block under <code>testOptions</code> to
+            configure customized tasks for unit test. The following sample code shows how to add
+            unit test configuration settings using this new option:
+<pre>
+android {
+  testOptions {
+    unitTest.all {
+      jvmArgs '-XX:MaxPermSize=256m' // Or any other gradle option.
+    }
+  }
+}
+</pre>
+           </li>
+          <li>Fixed the handling of enums and public instance fields in the packaging of the
+           <code>mockable-android.jar</code> file.
+          </li>
+          <li>Fixed library project task dependencies so test classes recompile after changes.
+          </li>
+          </ul>
+        <li>Added the <code>testProguardFile</code> property to apply
+          <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> files when minifying a test APK.
+        </li>
+        <li>Added the <code>timeOut</code> property to the <code>adbOptions</code> code block
+          for setting the maximum recording time for
+          <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> screen recording.
+        </li>
+        <li>Added support for 280 dpi resources.
+        </li>
+        <li>Improved performance during project evaluation.
+        </li>
+     </ul>
+    </dd>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Plugin for Gradle, Revision 1.1.3</a> <em>(March 2015)</em>
   </p>
 
diff --git a/docs/html/tools/revisions/index.jd b/docs/html/tools/revisions/index.jd
index 0e7ceef..0b8db83 100644
--- a/docs/html/tools/revisions/index.jd
+++ b/docs/html/tools/revisions/index.jd
@@ -6,4 +6,8 @@
 an update at their own schedule, so some have their own set of release notes. You can
 find information about some of the packages in this section, including the core <a
 href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools</a> and the latest <a
-href="{@docRoot}tools/revisions/platforms.html">Platforms</a>.</p>
\ No newline at end of file
+href="{@docRoot}tools/revisions/platforms.html">SDK Platforms</a>. Release notes are also available
+for Android developer tools, such as
+<a href="{@docRoot}tools/revisions/studio.html">Android Studio</a> and the
+<a href="{@docRoot}tools/revisions/gradle-plugin.html">Android Plugin for Gradle</a>.
+</p>
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index 3982f2e..4f153e3 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -29,9 +29,9 @@
 <p>For an introduction to Android Studio, read the
 <a href="{@docRoot}tools/studio/index.html">Android Studio</a> guide.</p>
 
-<p>Periodic updates are pushed to Android Studio without requiring you to update. To
-manually check for updates, select <strong>Help > Check for updates</strong> (on Mac, select
-<strong>Android Studio > Check for updates</strong>).</p>
+<p>Periodic updates are pushed to Android Studio without requiring you to update your Android
+project. To manually check for updates, select <strong>Help > Check for updates</strong> (on Mac,
+select <strong>Android Studio > Check for updates</strong>).</p>
 
 
 <h2 id="Revisions">Revisions</h2>
@@ -43,6 +43,53 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v1.2.0</a> <em>(April 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <p>Various fixes and enhancements:</p>
+    <ul>
+      <li>Updated the Android runtime window to include the
+        <a href="{@docRoot}tools/studio/index.html#memory-monitor">Memory Monitor</a> tool
+        and added a tab for CPU performance monitoring.</li>
+      <li>Added a <em>Captures</em> tab in the left margin to display the captured memory and CPU
+        performance data files, such as CPU method tracking and memory heap snapshots.</li>
+      <li>Expanded <a href="{@docRoot}tools/debugging/annotations.html">annotation</a>
+          support with additional metadata annotations and inferred nullability. </li>
+      <li>Enhanced the Translations Editor with additional support for Best Current Practice
+          (BCP) 47, which uses 3-letter language and region codes.</li>
+      <li>Integrated IntelliJ 14 and 14.1 features for improved code analysis and performance:</li>
+         <ul>
+          <li>Enhanced debugging to show inline values for variables and referring objects,
+            as well as perform inline evaluation of lambda and operator expressions. </li>
+          <li>Added code style detection for tab and indent sizes. </li>
+          <li>Added scratch files for code experiments and prototyping without project files.</li>
+          <li>Added the simultaneous insertion of opening and closing tags in HTML and XML files.</li>
+          <li>Added a built-in Java class decompiler so you can look at what’s inside a library
+            for which the source code is not available. </li>
+         </ul>
+         <p>See
+         <a class="external-link" href="https://www.jetbrains.com/idea/whatsnew">What's New in IntelliJ</a>
+         for a complete description of the new features and enhancements.</p>
+       </li>
+      <li>Added additional <a href="{@docRoot}tools/studio/index.html#project-view">Project Views</a>
+        for <em>Scratches</em>, <em>Project Files</em>, <em>Problems</em>, <em>Production</em>,
+        and <em>Tests</em> to enhance project management and access. </li>
+      <li>Enhanced the <strong>File &gt; Settings</strong> menu and dialogs for improved settings
+          access and management. </li>
+      <li>Added support for high-density displays for Windows and Linux. </li>
+      <li>Added support for 280 dpi resources in the <code>res/drawable-280dpi/</code> folder.
+     </ul>
+    </ul>
+  </div>
+</div>
+
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v1.1.0</a> <em>(February 2015)</em>
   </p>
 
@@ -63,6 +110,7 @@
       for region and language combinations, launcher icons, resource names, and other common
       code problems.</li>
       <li>Added support for Best Current Practice (BCP) language tag 47.  </li>
+    </ul>
   </div>
 </div>
 
@@ -85,6 +133,7 @@
       updates, use <strong>File > Settings > Updates</strong> to change to the <strong>Stable</strong>
       update channel.
       </li>
+    </ul>
   </div>
 </div>
 
diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd
index 1860feb..95cdb76 100644
--- a/docs/html/tools/studio/index.jd
+++ b/docs/html/tools/studio/index.jd
@@ -18,7 +18,7 @@
 
   <h2>See also</h2>
   <ol>
-    <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li>
+    <li><a class="external-link" href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li>
   </ol>
 
 </div>
@@ -26,8 +26,7 @@
 
 
 <p>Android Studio is the official IDE for Android application development,
-based on <a href="https://www.jetbrains.com/idea/" class="external-link"
-target="_blank">IntelliJ IDEA</a>.
+based on <a class="external-link" href="https://www.jetbrains.com/idea/" target="_blank">IntelliJ IDEA</a>.
 On top of the capabilities you expect from IntelliJ,
 Android Studio offers:</p>
 
@@ -38,10 +37,9 @@
   <li>Rich layout editor with support for drag and drop theme editing</li>
   <li>{@code lint} tools to catch performance, usability, version compatibility, and other problems</li>
   <li>ProGuard and app-signing capabilities</li>
-  <li>Built-in support for <a
-  href="http://developers.google.com/cloud/devtools/android_studio_templates/"
-  class="external-link">Google Cloud Platform</a>, making it easy to integrate Google Cloud
-  Messaging and App Engine</li>
+  <li>Built-in support for
+  <a href="http://developers.google.com/cloud/devtools/android_studio_templates/">Google Cloud Platform</a>,
+  making it easy to integrate Google Cloud Messaging and App Engine</li>
   <li>And much more</li>
 </ul>
 
@@ -62,17 +60,17 @@
 
 <h2 id="project-structure">Project and File Structure</h2>
 
-<h3 id="project-view"><em>Android</em> Project View</h3>
-<p>By default, Android Studio displays your profile files in the <em>Android</em> project view. This
+<h3 id="project-view"><em>Android</em> project view</h3>
+<p>By default, Android Studio displays your project files in the <em>Android</em> project view. This
 view shows a flattened version of your project's structure that provides quick access to the key
 source files of Android projects and helps you work with the
 <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>.
-The Android project view:</p>
+The <em>Android</em> project view:</p>
 
 <ul>
-  <li>Groups the build files for all modules at the top level of the project hierarchy.</li>
   <li>Shows the most important source directories at the top level of the module hierarchy.</li>
-  <li>Groups all the manifest files for each module.</li>
+  <li>Groups the build files for all modules in a common folder.</li>
+  <li>Groups all the manifest files for each module in a common folder.</li>
   <li>Shows resource files from all Gradle source sets.</li>
   <li>Groups resource files for different locales, orientations, and screen types in a single
   group per resource type.</li>
@@ -81,7 +79,7 @@
      <img src="{@docRoot}images/tools/projectview01.png" />
      <p class="img-caption"><strong>Figure 1.</strong> Show the Android project view.</p>
      <img src="{@docRoot}images/tools/studio-projectview_scripts.png"  />
-     <p class="img-caption"><strong>Figure 2.</strong> Project Build Files.</p>
+     <p class="img-caption"><strong>Figure 2.</strong> Show project build Files.</p>
 
 <p>The <em>Android</em> project view shows all the build files at the top level of the project
 hierarchy under <strong>Gradle Scripts</strong>. Each project module appears as a folder at the
@@ -91,18 +89,19 @@
   <li><code>java/</code> - Source files for the module.</li>
   <li><code>manifests/</code> - Manifest files for the module.</li>
   <li><code>res/</code> - Resource files for the module.</li>
+  <li><code>Gradle Scripts/</code> - Gradle build and property files.</li>
 </ul>
 
 <p>For example, <em>Android</em> project view groups all the instances of the
 <code>ic_launcher.png</code> resource for different screen densities under the same element.</p>
 
 <p class="note"><strong>Note:</strong> The project structure on disk differs from this flattened
-representation. To switch to back to the segregated project view, select <strong>Project</strong> from
-the <strong>Project</strong> drop-down. </p>
+representation. To switch to back to the segregated project view, select <strong>Project</strong>
+from the <strong>Project</strong> drop-down. </p>
 
 
-<h3>Android Studio Project and Directory Structure</h3>
-<p>When you use the <em>Project</em> view of a new project in Android Studio, you
+<h3 id="other-views">Other Android Studio views</h3>
+<p>When you use the <em>Project</em> view in Android Studio, you
 should notice that the project structure appears different than you may be used to in Eclipse. Each
 instance of Android Studio contains a project with one or more application modules. Each
 application module folder contains the complete source sets for that module, including
@@ -112,11 +111,28 @@
 specification and the files under {@code src/androidTest} directory for test case creation.
 
     <p>  <img src="{@docRoot}images/tools/studio-project-layout.png" alt="" /></p>
-    <p>  <class="img-caption"><strong>Figure 3.</strong> Android Studio project structure</p>
+    <p>  <class="img-caption"><strong>Figure 3.</strong> View Android Studio <em>Project</em>
+         structure.</p>
+
+<p>You can also customize the view of the project files to focus on specific aspects of your app
+development: </p>
+
+<ul>
+  <li><em>Packages</em> </li>
+  <li><em>Project Files</em> </li>
+  <li><em>Scratches</em> </li>
+  <li><em>Problems</em> </li>
+  <li><em>Production</em> </li>
+  <li><em>Tests</em> </li>
+</ul>
+
+<p>For example, selecting the <strong>Problems</strong> view of your project displays links to the
+source files containing any recognized coding and syntax errors, such as missing a XML element
+closing tag in a layout file.<p>
 
 <p>For more information, see
-<a href="http://confluence.jetbrains.com/display/IntelliJIDEA/Project+Organization"class="external-link">IntelliJ project organization</a> and
-<a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.</p>
+<a class="external-link" href="http://confluence.jetbrains.com/display/IntelliJIDEA/Project+Organization">IntelliJ project organization</a>
+and <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.</p>
 
 
 
@@ -155,7 +171,7 @@
 <a href="{@docRoot}tools/building/configuring-gradle.html">Configuring Gradle Builds</a>.</p>
 
 
-<h3>Application ID for Package Identification </h3>
+<h3>Application ID for package identification </h3>
 <p>With the Android build system, the <em>applicationId</em> attribute is used to
 uniquely identify application packages for publishing. The application ID is set in the
 <em>android</em> section of the <code>build.gradle</code> file.
@@ -209,7 +225,7 @@
    <pre>
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-   <strong>package="com.example.app"</strong>>
+   <strong>package="com.example.app"</strong>
    </pre>
 
 <p class="note"><strong>Note:</strong> If you have multiple manifests (for example, a product
@@ -242,25 +258,60 @@
 <p>For more information, see <a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs</a>.</p>
 
 
+<h3 id="inline-debug">Inline debugging</h3>
+<p>Use inline debugging to enhance your code walk-throughs in the debugger view
+with inline verification of references, expressions, and variable values. Inline debug information
+includes: </p>
+<ul>
+ <li>Inline variable values</li>
+ <li>Referring objects that reference a selected object </li>
+ <li>Method return values</li>
+ <li>Lambda and operator expressions</li>
+ <li>Tool tip values</li>
+</ul>
 
-<h3>Memory Monitor</h3>
+<p>To enable inline debugging, in the <em>Debug</em> window click the Settings icon
+<img src="{@docRoot}images/tools/studio-debug-settings-icon.png"/> and select the
+check box for <strong>Show Values In Editor</strong>.</p>
+
+<h3 id="mem-cpu">Memory and CPU monitor</h3>
+<p>Android Studio provides a memory and CPU monitor view so you can more easily monitor your
+app's performance and memory usage to track CPU usage, find deallocated objects, locate memory
+leaks, and track the amount of memory the connected device is using. With your app running on a
+device or emulator, click the <strong>Android</strong> tab in the lower left corner of the
+runtime window to launch the Android runtime window. Click the <strong>Memory</strong> or
+<strong>CPU</strong> tab. </p>
+
+
+<h3 id="memory-monitor">Memory Monitor</h3>
 <p>Android Studio provides a memory monitor view so you can more easily monitor your
 app's memory usage to find deallocated objects, locate memory leaks and track the amount of
 memory the connected device is using. With your app running on a device or emulator, click the
 <strong>Memory Monitor</strong> tab in the lower right corner to launch the memory monitor. </p>
 
-    <img src="{@docRoot}images/tools/studio-memory-monitor.png" />
-    <p class="img-caption"><strong>Figure 5.</strong> Memory Monitor</p>
+<img src="{@docRoot}images/tools/studio-memory-monitor.png" srcset="{@docRoot}images/tools/studio-memory-monitor_2x.png 2x" width"635" height="171" alt="" />
+    <p class="img-caption"><strong>Figure 4.</strong> Monitor memory and CPU usage.</p>
 
 
+<h3>Data file access</h3>
+<p>The Android SDK tools, such as <a href="{@docRoot}tools/help/systrace.html">Systrace</a>,
+<a href="{@docRoot}tools/help/logcat.html">logcat</a>, and
+<a href="{@docRoot}tools/help/traceview.html">Traceview</a>, generate performance and debugging
+data for detailed app analysis.</p>
 
-<h3>Code Inspections</h3>
-<p>In Android Studio, the configured <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a> and
-other IDE inspections run automatically whenever you compile your program. In addition to the
+<p>To view the available generated data files, click <strong>Captures</strong> in the left
+corner of the runtime window. In the list of the generated files, double-click a file to view
+the data. Right-click any <code>.hprof</code> files to convert them to a standard
+<a href="{@docRoot}tools/help/hprof-conv.html"><code>.hprof</code> </a> file format.</p>
+
+
+<h3>Code inspections</h3>
+<p>In Android Studio, the configured <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a>
+and other IDE inspections run automatically whenever you compile your program. In addition to the
 configured {@code lint} checks, additional
-<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
-target="_blank">IntelliJ code inspections</a>
-run to streamline code review.</p>
+<a class="external-link" href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection"
+target="_blank">IntelliJ code inspections</a> and annotation validation run to streamline code
+review.</p>
 
 
 <p>Android Studio enables several <code>lint</code> checks
@@ -268,10 +319,10 @@
 <ul>
   <li><code> Cipher.getInstance()</code> is used with safe values</li>
   <li>In custom Views, the associated declare-styleable for the custom view uses the same
-  base name as the class name.</li>
-  <li>Security check for fragment injection.</li>
-  <li>Where ever property assignment no longer works as expected.</li>
-  <li>Gradle plugin version is compatible with the SDK.</li>
+  base name as the class name</li>
+  <li>Security check for fragment injection</li>
+  <li>Where ever property assignment no longer works as expected</li>
+  <li>Gradle plugin version is compatible with the SDK</li>
   <li>Right to left validation </li>
   <li>Required API version</li>
   <li>many others</li>
@@ -301,13 +352,13 @@
 
 
 <p>You can also manage inspection profiles and configure inspections within Android Studio.
-Choose <strong>File &gt; Settings &gt; Project Settings</strong>. The
-<em>Inspection Configuration</em> page appears with the supported inspections.</p>
+Choose <strong>File &gt; Settings &gt; Project Settings</strong> and expand <strong>Editor</strong>.
+The <em>Inspection Configuration</em> page appears with the supported inspections.</p>
 <p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
-<p class="img-caption"><strong>Figure 5.</strong> Inspection Configuration</p> 
+<p class="img-caption"><strong>Figure 5.</strong> Configure inspections.</p>
 
-<p class="note"><strong>Note:</strong> If you wish to change the behavior of specific
-inspection notifications, you can change the inspection severity, for example from <em>warning</em>
+<p class="note"><strong>Note:</strong> To change the behavior of specific
+inspection notifications, change the inspection severity, for example from <em>warning</em>
 to <em>error</em>. </p>
 
 
@@ -316,7 +367,7 @@
 
 
 
-<h4>Running Inspections from the command line</h4>
+<h4>Running inspections from the command line</h4>
 <p>You can also run {@code lint} inspections from the command line in your SDK directory. </p>
 <pre>
 sdk$ lint [flags] <project directories>
@@ -327,25 +378,127 @@
 
 
 <p>For more information, see
-<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with {@code lint}</a> and
-<a href="{@docRoot}tools/help/lint.html">lint tool</a>.</p>
+<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with {@code lint}</a>
+and <a href="{@docRoot}tools/help/lint.html">lint tool</a>.</p>
+
+
+
+<h3 id="annotations">Annotations in Android Studio</h3>
+<p>Android Studio supports annotations for variables, parameters, and return values to help you
+catch bugs, such as null pointer exceptions and resource type conflicts. The
+<a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a> packages
+the {@link android.support.annotation Support-Annotations} library
+in the Android Support Repository for use with Android
+Studio. Android Studio validates the configured annotations during code inspection. </p>
+
+<p>To add annotations to your code in Android Studio, first add a dependency for the
+{@link android.support.annotation Support-Annotations} library:</p>
+<ol>
+ <li>Select <strong>File &gt; Project Structure</strong>.</li>
+ <li>In the <em>Project Structure</em> dialog, select the desired module, click the
+ <strong>Dependencies</strong> tab. </li>
+ <li>Click the <img src="{@docRoot}images/tools/studio-add-icon.png"/> icon to include a
+ <strong>Library dependency</strong>.</li>
+ <li>In the <em>Choose Library Dependency</em> dialog, select <code>support-annotations</code> and
+ click <strong>Ok</strong>. </li>
+</ol> 
+
+<p>The <code>build.gradle</code> file is updated with the <code>support-annotations</code>
+dependency.</p>
+
+<p>You can also manually add this dependency to your <code>build.gradle</code> file, as shown in
+the following example.  </p>
+
+<pre>
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:22.0.0'
+    <strong>compile 'com.android.support:support-annotations:22.0.0'</strong>
+}
+</pre>
+
+
+
+<h4>Inferring nullability</h4>
+<p>A nullability analysis scans the contracts throughout the method hierarchies in your code to
+detect:</p>
+<ul>
+ <li>Calling methods that can return null </li>
+ <li>Methods that should not return null </li>
+ <li>Variables, such as fields, local variables, and parameters, that can be null </li>
+ <li>Variables, such as fields, local variables, and parameters, that cannot hold a null value </li>
+</ul>
+
+<p>The analysis then automatically inserts the appropriate null annotations in the detected
+locations. </p>
+
+<p>To run a nullability analysis in Android Studio,
+select the <strong>Analyze &gt; Infer Nullity</strong>
+menu option. Android Studio inserts the Android
+{@link android.support.annotation.Nullable @Nullable} and
+{@link android.support.annotation.NonNull @NonNull} annotations in detected locations
+in your code. After running a null analysis, it's good practice to verify the injected
+annotations.</p>
+
+<p class="note"><strong>Note:</strong> The nullability analysis may insert the IntelliJ
+<a class="external-link" href="https://www.jetbrains.com/idea/help/-nullable-and-notnull-annotations.html?search=annotations">
+<code>&#64;Nullable</code></a> and
+<a class="external-link" href="https://www.jetbrains.com/idea/help/-nullable-and-notnull-annotations.html?search=annotations">
+<code>&#64;NotNull</code></a> annotations instead of the Android null annotations. When running
+a null analysis, manually search and replace any IntelliJ annotations or include
+<code>com.intellij:annotations:12.0</code> as a compile dependency in your
+<code>build.gradle</code> file. This example includes the IntelliJ annotations 12.0 library as a
+dependency in the <code>build.gradle</code> file:
+
+<pre>
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:22.0.0'
+    compile 'com.android.support:support-annotations:22.0.0'
+    <strong>compile 'com.intellij:annotations:12.0'</strong>
+}
+</pre>
+
+</p>
+
+
+<h4>Validating annotations</h4>
+<p>You can also manually add nullability, resource, and enumerated annotations throughout your code
+to perform validations for a variety of reference values, such as
+<a href="{@docRoot}reference/android/R.string.html"><code>R.string</code></a> resources,
+<a href="{@docRoot}guide/topics/resources/drawable-resource.htm"><code>Drawable</code></a>
+resources,
+<a href="{@docRoot}reference/android/graphics/Color.html"><code>Color</code></a> resources,
+and enumerated constants. </p>
+
+<p>Run <strong>Analyze &gt; Inspect Code</strong> to validate the configured annotations. </p>
+
+<p>For a complete list of the supported annotations, either use the auto-complete feature to display
+the available options for the <code>import android.support.annotation.</code> statement or
+view the contents of the
+{@link android.support.annotation Support-Annotations}
+library. </p>
+
+<p>For more details about Android annotations, see
+<a href="{@docRoot}tools/debugging/annotations.html">Improving Code Inspection with Annotations</a>.
+
 
 
 <h3>Dynamic layout preview</h3>
 <p>Android Studio allows you to work with layouts in both a <em>Design View</em> </p>
 <p><img src="{@docRoot}images/tools/studio-helloworld-design.png" alt="" />
 </p>
-    <p class="img-caption"><strong>Figure 6.</strong> Hello World App with Design View</p>
+    <p class="img-caption"><strong>Figure 6.</strong> Hello World App with Design View.</p>
 
 <p>and a <em>Text View</em>. </p>
 
     <p><img src="{@docRoot}images/tools/studio-helloworld-text.png" alt="" />
-    <pclass="img-caption"><strong>Figure 7.</strong> Hello World App with Text View</p>
+    <pclass="img-caption"><strong>Figure 7.</strong> Hello World App with text view.</p>
 
 <p>Easily select and preview layout changes for different device images, display
 densities, UI modes, locales, and Android versions (multi-API version rendering).
     <p><img src="{@docRoot}images/tools/studio-api-version-rendering.png" /></p>
-    <p class="img-caption"><strong>Figure 8.</strong> API Version Rendering</p>
+    <p class="img-caption"><strong>Figure 8.</strong> Multi-API version rendering.</p>
 
 
 <p>From the Design View, you can drag and drop elements from the Palette to the Preview or
@@ -372,17 +525,17 @@
 <h2 id="install-updates">Installation, Setup, and Update Management</h2>
 
 <h3>Android Studio installation and setup wizards</h3>
-<p>An updated installation and setup wizards walk you through a step-by-step installation
-and setup process as the wizard checks for system requirements, such as the Java Development
-Kit (JDK) and available RAM, and then prompts for optional installation options, such as the
-Intel&#174; HAXM emulator accelerator.</p>
+<p>When you begin the installation process, an installation and setup wizard walks you through
+a step-by-step installation and setup process as the wizard checks for system requirements,
+such as the Java Development Kit (JDK) and available RAM, and then prompts for optional
+installation options, such as the Intel&#174; HAXM emulator accelerator.</p>
 
-<p>An updated setup wizard walks you through the setup processes as
+<p>During the installation process, a setup wizard walks you through the setup processes as
 the wizard updates your system image and emulation requirements, such GPU, and then creates
 an optimized default Android Virtual Device (AVD) based on Android 5 (Lollipop) for speedy and
 reliable emulation. </p>
 <p><img src="{@docRoot}images/tools/studio-setup-wizard.png" /></p>
-<p class="img-caption"><strong>Figure 9.</strong> Setup Wizard</p>
+<p class="img-caption"><strong>Figure 9.</strong> Installation and setup wizard.</p>
 
 
 <h3>Expanded template and form factor support</h3>
@@ -390,11 +543,11 @@
 types. </p>
 
     <h4> Android Wear and TV support</h4>
-    <p>For easy cross-platform development, the Project Wizard provides new templates for
+    <p>For easy cross-platform development, the Project Wizard provides templates for
     creating your apps for Android Wear and TV. </p>
     <p><img src="{@docRoot}images/tools/studio-tvwearsupport.png"  />
 
-      <p class="img-caption"><strong>Figure 10.</strong> Supported Form Factors</p>
+      <p class="img-caption"><strong>Figure 10.</strong> Supported form factors.</p>
     <p>During app creation, the Project Wizard also displays an API Level dialog to help you choose
     the best <em>minSdkVersion</em> for your project.</p>
 
@@ -404,7 +557,26 @@
     and create a cloud end-point is as easy as selecting <em>File > New Module > App Engine Java
     Servlet Module</em> and specifying the module, package, and client names. </p>
     <p><img src="{@docRoot}images/tools/studio-cloudmodule.png" /></p>
-    <p class="img-caption"><strong>Figure 11.</strong> Setup Wizard</p>
+    <p class="img-caption"><strong>Figure 11.</strong> Google App Engine integration.</p>
+
+
+<h3>Easy access to project and file settings</h3>
+<p>Android Studio provides setting dialogs so you can manage the most important project and file
+settings from the <strong>File</strong> menus as well as the build and configuration files. For
+example, you can use the <strong>File &gt; Project Structure</strong> menu or
+the <code>build.gradle</code> file to update your <code>productFlavor</code> settings.
+Additional settings from the <strong>File</strong> menus include:
+<ul>
+ <li>SDK and JDK location </li>
+ <li>SDK version </li>
+ <li>Gradle and Android Plugin for Gradle versions </li>
+ <li>Build tools version </li>
+ <li>Multidex setting</li>
+ <li>Product flavors </li>
+ <li>Build types </li>
+ <li>Dependencies </li>
+</ul>
+</p>
 
 
 
@@ -451,13 +623,14 @@
 <p>Android Studio supports HTTP proxy settings so you can run Android Studio behind a firewall or
 secure network. To set the HTTP proxy settings in Android Studio:</p>
 <ol>
- <li>From the main menu choose <strong>File &gt; Settings &gt; IDE Setting -- HTTP Proxy</strong>.
+ <li>From the main menu choose <strong>File &gt; Settings &gt; Appearance & Behavior -- System
+ Settings -- HTTP Proxy</strong>.
 
 <li>In Android Studio, open the IDE Settings dialog.
   <ul>
-     <li>On Windows and Linux, choose 
+     <li>On Windows and Linux, choose
      <strong>File &gt; Settings &gt; IDE Setting -- HTTP Proxy</strong>. </li>
-     <li>On Mac, choose 
+     <li>On Mac, choose
      <strong>Android Studio &gt; Preferences &gt; IDE Setting -- HTTP Proxy</strong>. </li>
    </ul>
  The HTTP Proxy page appears.</li>
@@ -544,36 +717,39 @@
 
 <h2 id="other">Other Highlights</h2>
 
-<h3> Translation Editor</h3>
-<p>Multi-language support is enhanced with the Translation Editor plugin so you can easily add
-locales to the app's translation file. Color codes indicate whether a locale is complete or
-still missing string translations. Also, you can use the plugin to export your strings to the
-Google Play Developer Console for translation, then download and import your translations back
-into your project. </p>
+<h3 id="trans-editor"> Translations Editor</h3>
+<p>Multi-language support is enhanced with the Translations Editor plugin so you can easily add
+a variety of locales to the app's translation file. With
+<a href="https://tools.ietf.org/html/bcp47">BCP 47</a> support, the editor combines language and
+region codes into a single selection for targeted localizations. Color codes indicate whether a
+locale is complete or still missing string translations. You can also use the plugin to export
+your strings to the
+<a href="{@docRoot}distribute/googleplay/developer-console.html">Google Play Developer Console</a>
+for translation, then download and import your translations back into your project. </p>
 
-<p>To access the Translation Editor, open a <code>strings.xml</code> file and click the
+<p>To access the Translations Editor, open a <code>strings.xml</code> file and click the
 <strong>Open Editor</strong> link.  </p>
 
     <img src="{@docRoot}images/tools/studio-translationeditoropen.png" />
-    <p class="img-caption"><strong>Figure 12.</strong> Translation Editor</p>
+    <p class="img-caption"><strong>Figure 12.</strong> Add locales and strings in the
+    Translations Editor.</p>
 
 
 <h3> Editor support for the latest Android APIs</h3>
 <p>Android Studio supports the
 <a href="{@docRoot}design/material/index.html">Material Design</a></li> themes, widgets, and
 graphics, such as shadow layers and API version rendering (showing the layout across different
-UI versions). Also, the drawable XML tags and attributes, such as &lt;ripple&gt;
-and &lt;animated-selector&gt;, are supported.</p>
+UI versions). Also, the drawable XML tags and attributes, such as <code>&lt;ripple&gt;</code>
+and <code>&lt;animated-selector&gt;</code>, are supported.</p>
 
 
 <h3 id="git-samples"> Easy access to Android code samples on GitHub</h3>
-<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or <em>Welcome</em> page
-
-provides seamless access to Google code samples on GitHub.</p>
+<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or <em>Welcome</em>
+page provides seamless access to Google code samples on GitHub.</p>
     <p><img src="{@docRoot}images/tools/studio-samples-githubaccess.png" /></p>
-    <p class="img-caption"><strong>Figure 13.</strong> Code Sample Access</p>
+    <p class="img-caption"><strong>Figure 13.</strong> Get code samples from GitHub.</p>
 
     <p><img src="{@docRoot}images/tools/studio-sample-in-editor.png" /></p>
-    <p class="img-caption"><strong>Figure 14.</strong> Imported Code Sample</p>
+    <p class="img-caption"><strong>Figure 14.</strong> Imported code sample.</p>
 
 
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 3f4b111..88a2674 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -128,6 +128,7 @@
       <li><a href="<?cs var:toroot ?>tools/debugging/improving-w-lint.html"><span class="en">Improving Your Code with lint</span></a></li>
       <li><a href="<?cs var:toroot ?>tools/debugging/debugging-ui.html"><span class="en">Optimizing your UI</span></a></li>
       <li><a href="<?cs var:toroot ?>tools/debugging/debugging-tracing.html"><span class="en">Profiling with Traceview and dmtracedump</span></a></li>
+      <li><a href="<?cs var:toroot ?>tools/debugging/annotations.html"><span class="en">Improving Code Inspection with Annotations</span></a></li>
       <li><a href="<?cs var:toroot ?>tools/debugging/systrace.html"><span class="en">Analyzing Display and Performance</span></a></li>
       <li><a href="<?cs var:toroot ?>tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a></li>
       <li><a href="<?cs var:toroot ?>tools/debugging/debugging-devtools.html"><span class="en">Using the Dev Tools App</span></a></li>
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index a4fc2d2..217db81 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -29,7 +29,9 @@
 <p>The Android Keystore system lets you store cryptographic keys in a container
   to make it more difficult to extract from the device. Once keys are in the
   keystore, they can be used for cryptographic operations with the key material
-  remaining non-exportable.</p>
+  remaining non-exportable. Moreover, it offers facilities to restrict when and
+  how keys can be used, such as requiring user authentication for key use or
+  restricting encryption keys to be used only in certain block modes.</p>
 
 <p>The Keystore system is used by the {@link
   android.security.KeyChain} API as well as the Android
@@ -112,3 +114,27 @@
 <p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p>
 
 {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify}
+
+<h3 id="UserAuthentication">Requiring User Authentication For Key Use</h3>
+
+<p>When generating or importing a key into the {@code AndroidKeyStore} you can specify that the key
+can only be used if user has been authenticated. The user is authenticated using a subset of their
+secure lock screen credentials. This is a security measure which makes it possible to generate
+cryptographic assertions about the user having been authenticated.
+
+<p>When a key is configured to require user authentication, it is also configured to operate in one
+of the two modes:
+<ul>
+<li>User authentication is valid for a duration of time. All keys in this mode are authorized
+  for use as soon as the user unlocks the secure lock screen or confirms their secure lock screen
+  credentials using the {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent}
+  flow. Each key specifies for how long the authorization remains valid for that key. Such keys
+  can only be generated or imported if the secure lock screen is enabled (see {@link android.app.KeyguardManager#isKeyguardSecure Keyguard.isKeyguardSecure}).
+  These keys become permanently invalidated once the secure lock screen is disabled or forcibly
+  reset (e.g. by a Device Admin).</li>
+<li>User authentication is required for every use of the key. In this mode, a specific operation
+  involving a specific key is authorized by the user. Currently, the only means of such
+  authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, int) FingerprintManager.authenticate}.
+  Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}).
+  These keys become permanently invalidated once all fingerprints are unenrolled.</li>
+</ul>
diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd
index 043aff2..ef9bfb1 100644
--- a/docs/html/training/wearables/data-layer/messages.jd
+++ b/docs/html/training/wearables/data-layer/messages.jd
@@ -34,7 +34,7 @@
 
 <p>Multiple wearable devices can be connected to a user’s handheld device. Each connected device in
 the network is considered a <em>node</em>. With multiple connected devices, you must consider which
-nodes receive the messages. For example, In a voice transcription app that receives voice data on
+nodes receive the messages. For example, in a voice transcription app that receives voice data on
 the wearable device, you should send the message to a node with the processing power and battery
 capacity to handle the request, such as a handheld device.</p>
 
@@ -196,7 +196,15 @@
 
 <p>The following example shows how to send a message to the transcription-capable node from a
 wearable device. Verify that the node is available before you attempt to send the message. This call
-is synchronous and blocks processing until the message is received or until the request times out.
+is synchronous and blocks processing until the system queues the message for delivery.
+</p>
+
+<p class="note"><strong>Note:</strong> A successful result code does not guarantee delivery of the
+message. If your app requires data reliability, use
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a>
+objects or the
+<a href="{@docRoot}reference/com/google/android/gms/wearable/ChannelApi.html"><code>ChannelApi</code></a>
+class to send data between devices.
 </p>
 
 <pre>
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index f2f890e..bd74bc8 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,8 +42,7 @@
         mBitmap = bitmap;
         mTileX = tileX;
         mTileY = tileY;
-        final long b = bitmap.getSkBitmap();
-        init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
+        init(nativeCreate(bitmap, tileX.nativeInt, tileY.nativeInt));
     }
 
     /**
@@ -56,6 +55,6 @@
         return copy;
     }
 
-    private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
+    private static native long nativeCreate(Bitmap bitmap, int shaderTileModeX,
             int shaderTileModeY);
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 9fe8e0c..7a1ecf7 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -81,10 +81,6 @@
      */
     protected int mScreenDensity = Bitmap.DENSITY_NONE;
 
-    // Used by native code
-    @SuppressWarnings("UnusedDeclaration")
-    private int mSurfaceFormat;
-
     // Maximum bitmap size as defined in Skia's native code
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 4c2817c..dc9aa67 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -133,7 +133,7 @@
 
     private GradientState mGradientState;
 
-    private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final Paint mFillPaint = new Paint();
     private Rect mPadding;
     private Paint mStrokePaint;   // optional, set by the caller
     private ColorFilter mColorFilter;   // optional, set by the caller
@@ -323,7 +323,7 @@
 
     private void setStrokeInternal(int width, int color, float dashWidth, float dashGap) {
         if (mStrokePaint == null)  {
-            mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mStrokePaint = new Paint();
             mStrokePaint.setStyle(Paint.Style.STROKE);
         }
         mStrokePaint.setStrokeWidth(width);
@@ -1802,7 +1802,7 @@
         mPadding = state.mPadding;
 
         if (state.mStrokeWidth >= 0) {
-            mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mStrokePaint = new Paint();
             mStrokePaint.setStyle(Paint.Style.STROKE);
             mStrokePaint.setStrokeWidth(state.mStrokeWidth);
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 3bbbc71..e5b4612 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -564,8 +564,6 @@
 
         if (drawable != null) {
             drawable.setCallback(this);
-            drawable.setLayoutDirection(getLayoutDirection());
-            drawable.setLevel(getLevel());
         }
 
         childDrawable.mDrawable = drawable;
@@ -1464,7 +1462,8 @@
                     bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);
 
             // Apply resolved gravity to drawable based on resolved size.
-            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight);
+            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight,
+                    d.getIntrinsicWidth(), d.getIntrinsicHeight());
             final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
             final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
             Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
@@ -1491,7 +1490,8 @@
      * @param height height of the layer if set, -1 otherwise
      * @return the default gravity for the layer
      */
-    private static int resolveGravity(int gravity, int width, int height) {
+    private static int resolveGravity(int gravity, int width, int height,
+            int intrinsicWidth, int intrinsicHeight) {
         if (!Gravity.isHorizontal(gravity)) {
             if (width < 0) {
                 gravity |= Gravity.FILL_HORIZONTAL;
@@ -1508,6 +1508,17 @@
             }
         }
 
+        // If a dimension if not specified, either implicitly or explicitly,
+        // force FILL for that dimension's gravity. This ensures that colors
+        // are handled correctly and ensures backward compatibility.
+        if (width < 0 && intrinsicWidth < 0) {
+            gravity |= Gravity.FILL_HORIZONTAL;
+        }
+
+        if (height < 0 && intrinsicHeight < 0) {
+            gravity |= Gravity.FILL_VERTICAL;
+        }
+
         return gravity;
     }
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 334b3bd..caa0787 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -501,7 +501,7 @@
             if (mShapeState.mPaint != null) {
                 mShapeState.mPaint = new Paint(mShapeState.mPaint);
             } else {
-                mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                mShapeState.mPaint = new Paint();
             }
             if (mShapeState.mPadding != null) {
                 mShapeState.mPadding = new Rect(mShapeState.mPadding);
@@ -555,7 +555,7 @@
                 mAlpha = orig.mAlpha;
                 mShaderFactory = orig.mShaderFactory;
             } else {
-                mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                mPaint = new Paint();
             }
         }
 
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index b32dcc6..feb8052 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -380,7 +380,7 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft,
+            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
                     contentTop, contentRight, contentBottom, transformPtr, renderMode);
         }
 
@@ -425,7 +425,7 @@
     private static native void nativeClose(long documentPtr);
     private static native int nativeGetPageCount(long documentPtr);
     private static native boolean nativeScaleForPrinting(long documentPtr);
-    private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
+    private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest,
             int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
     private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
             Point outSize);
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index c259c25..72cb062 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -486,16 +486,6 @@
             }
         }
         args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
-        if (keymasterDigests.length > 0) {
-            // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
-            // This code will blow up if mode than one digest is specified.
-            int digestOutputSizeBytes =
-                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]);
-            if (digestOutputSizeBytes != -1) {
-                // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
-                args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
-            }
-        }
         if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
             if (keymasterDigests.length == 0) {
                 throw new KeyStoreException("At least one digest algorithm must be specified"
@@ -529,27 +519,10 @@
                 KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings(
                         params.getSignaturePaddings()));
         args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
-        if (params.getUserAuthenticators() == 0) {
-            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        } else {
-            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
-                            params.getUserAuthenticators()));
-            long secureUserId = GateKeeper.getSecureUserId();
-            if (secureUserId == 0) {
-                throw new IllegalStateException("Secure lock screen must be enabled"
-                        + " to import keys requiring user authentication");
-            }
-            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, secureUserId);
-        }
-        if (params.isInvalidatedOnNewFingerprintEnrolled()) {
-            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
-            // that.
-        }
-        if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
-            args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
-                    params.getUserAuthenticationValidityDurationSeconds());
-        }
+        KeymasterUtils.addUserAuthArgs(args,
+                params.getContext(),
+                params.isUserAuthenticationRequired(),
+                params.getUserAuthenticationValidityDurationSeconds());
         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                 (params.getKeyValidityStart() != null)
                         ? params.getKeyValidityStart() : new Date(0));
diff --git a/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java
new file mode 100644
index 0000000..45329cf
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.Provider;
+
+/**
+ * {@link Provider} of JCA crypto operations operating on Android KeyStore keys.
+ *
+ * <p>This provider was separated out of {@link AndroidKeyStoreProvider} to work around the issue
+ * that Bouncy Castle provider incorrectly declares that it accepts arbitrary keys (incl. Android
+ * KeyStore ones). This causes JCA to select the Bouncy Castle's implementation of JCA crypto
+ * operations for Android KeyStore keys unless Android KeyStore's own implementations are installed
+ * as higher-priority than Bouncy Castle ones. The purpose of this provider is to do just that: to
+ * offer crypto operations operating on Android KeyStore keys and to be installed at higher priority
+ * than the Bouncy Castle provider.
+ *
+ * <p>Once Bouncy Castle provider is fixed, this provider can be merged into the
+ * {@code AndroidKeyStoreProvider}.
+ *
+ * @hide
+ */
+class AndroidKeyStoreBCWorkaroundProvider extends Provider {
+
+    // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
+    // classes when this provider is instantiated and installed early on during each app's
+    // initialization process.
+
+    private static final String PACKAGE_NAME = "android.security";
+    private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
+            PACKAGE_NAME + ".KeyStoreSecretKey";
+
+    AndroidKeyStoreBCWorkaroundProvider() {
+        super("AndroidKeyStoreBCWorkaround",
+                1.0,
+                "Android KeyStore security provider to work around Bouncy Castle");
+
+        // javax.crypto.Mac
+        putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
+        putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
+        putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
+        putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
+        putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
+
+        // javax.crypto.Cipher
+        putSymmetricCipherImpl("AES/ECB/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$NoPadding");
+        putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$PKCS7Padding");
+
+        putSymmetricCipherImpl("AES/CBC/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$NoPadding");
+        putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$PKCS7Padding");
+
+        putSymmetricCipherImpl("AES/CTR/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
+    }
+
+    private void putMacImpl(String algorithm, String implClass) {
+        put("Mac." + algorithm, implClass);
+        put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+    }
+
+    private void putSymmetricCipherImpl(String transformation, String implClass) {
+        put("Cipher." + transformation, implClass);
+        put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+    }
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 43f3b30..518067b 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
 package android.security;
 
 import java.security.Provider;
+import java.security.Security;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -32,10 +33,12 @@
     // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
     // classes when this provider is instantiated and installed early on during each app's
     // initialization process.
+    //
+    // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider.
+    // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
+    // for details.
 
     private static final String PACKAGE_NAME = "android.security";
-    private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
-            PACKAGE_NAME + ".KeyStoreSecretKey";
 
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -62,43 +65,39 @@
         putSecretKeyFactoryImpl("HmacSHA256");
         putSecretKeyFactoryImpl("HmacSHA384");
         putSecretKeyFactoryImpl("HmacSHA512");
+    }
 
-        // javax.crypto.Mac
-        putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
-        putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
-        putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
-        putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
-        putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
+    /**
+     * Installs a new instance of this provider (and the
+     * {@link AndroidKeyStoreBCWorkaroundProvider}).
+     */
+    public static void install() {
+        Provider[] providers = Security.getProviders();
+        int bcProviderPosition = -1;
+        for (int position = 0; position < providers.length; position++) {
+            Provider provider = providers[position];
+            if ("BC".equals(provider.getName())) {
+                bcProviderPosition = position;
+                break;
+            }
+        }
 
-        // javax.crypto.Cipher
-        putSymmetricCipherImpl("AES/ECB/NoPadding",
-                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$NoPadding");
-        putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
-                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$PKCS7Padding");
-
-        putSymmetricCipherImpl("AES/CBC/NoPadding",
-                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$NoPadding");
-        putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
-                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$PKCS7Padding");
-
-        putSymmetricCipherImpl("AES/CTR/NoPadding",
-                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
+        Security.addProvider(new AndroidKeyStoreProvider());
+        Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
+        if (bcProviderPosition != -1) {
+            // Bouncy Castle provider found -- install the workaround provider above it.
+            Security.insertProviderAt(workaroundProvider, bcProviderPosition);
+        } else {
+            // Bouncy Castle provider not found -- install the workaround provider at lowest
+            // priority.
+            Security.addProvider(workaroundProvider);
+        }
     }
 
     private void putSecretKeyFactoryImpl(String algorithm) {
         put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
     }
 
-    private void putMacImpl(String algorithm, String implClass) {
-        put("Mac." + algorithm, implClass);
-        put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
-    }
-
-    private void putSymmetricCipherImpl(String transformation, String implClass) {
-        put("Cipher." + transformation, implClass);
-        put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
-    }
-
     /**
      * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
      * primitive.
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index c9f06e9..5617836 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -15,13 +15,17 @@
     private GateKeeper() {}
 
     public static IGateKeeperService getService() {
-        return IGateKeeperService.Stub.asInterface(
+        IGateKeeperService service = IGateKeeperService.Stub.asInterface(
                 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
+        if (service == null) {
+            throw new IllegalStateException("Gatekeeper service not available");
+        }
+        return service;
     }
 
     public static long getSecureUserId() throws IllegalStateException {
         try {
-            return GateKeeper.getService().getSecureUserId(UserHandle.myUserId());
+            return getService().getSecureUserId(UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new IllegalStateException(
                     "Failed to obtain secure user ID from gatekeeper", e);
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 7ecc47e..8f135a6 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -51,9 +51,8 @@
     private final String[] mEncryptionPaddings;
     private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+    private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
     private KeyGeneratorSpec(
             Context context,
@@ -67,9 +66,8 @@
             String[] encryptionPaddings,
             String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
-            int userAuthenticationValidityDurationSeconds,
-            boolean invalidatedOnNewFingerprintEnrolled) {
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -92,9 +90,8 @@
                 ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
         mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticators = userAuthenticators;
+        mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -188,18 +185,17 @@
     }
 
     /**
-     * Gets the set of user authenticators which protect access to this key. The key can only be
-     * used iff the user has authenticated to at least one of these user authenticators.
+     * Returns {@code true} if user authentication is required for this key to be used.
      *
-     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     * @see #getUserAuthenticationValidityDurationSeconds()
      */
-    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
-        return mUserAuthenticators;
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
     }
 
     /**
-     * Gets the duration of time (seconds) for which this key can be used after the user
-     * successfully authenticates to one of the associated user authenticators.
+     * Gets the duration of time (seconds) for which this key can be used after the user is
+     * successfully authenticated.
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
@@ -209,17 +205,6 @@
     }
 
     /**
-     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
-     * enrolled. This constraint only has effect if fingerprint reader is one of the user
-     * authenticators protecting access to this key.
-     *
-     * @see #getUserAuthenticators()
-     */
-    public boolean isInvalidatedOnNewFingerprintEnrolled() {
-        return mInvalidatedOnNewFingerprintEnrolled;
-    }
-
-    /**
      * Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}.
      */
     public boolean isEncryptionRequired() {
@@ -238,9 +223,8 @@
         private String[] mEncryptionPaddings;
         private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+        private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
-        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -416,32 +400,35 @@
         }
 
         /**
-         * Sets the user authenticators which protect access to this key. The key can only be used
-         * iff the user has authenticated to at least one of these user authenticators.
+         * Sets whether user authentication is required to use this key.
          *
          * <p>By default, the key can be used without user authentication.
          *
-         * @param userAuthenticators user authenticators or empty list if this key can be accessed
-         *        without user authentication.
+         * <p>When user authentication is required, the user authorizes the use of the key by
+         * authenticating to this Android device using a subset of their secure lock screen
+         * credentials. Different authentication methods are used depending on whether the every
+         * use of the key must be authenticated (as specified by
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
+         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
+         * information</a>.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          */
-        public Builder setUserAuthenticators(
-                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
-            mUserAuthenticators = userAuthenticators;
+        public Builder setUserAuthenticationRequired(boolean required) {
+            mUserAuthenticationRequired = required;
             return this;
         }
 
         /**
-         * Sets the duration of time (seconds) for which this key can be used after the user
-         * successfully authenticates to one of the associated user authenticators.
+         * Sets the duration of time (seconds) for which this key can be used after the user is
+         * successfully authenticated. This has effect only if user authentication is required.
          *
          * <p>By default, the user needs to authenticate for every use of the key.
          *
          * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
          *        every use of the key.
          *
-         * @see #setUserAuthenticators(int)
+         * @see #setUserAuthenticationRequired(boolean)
          */
         public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
             mUserAuthenticationValidityDurationSeconds = seconds;
@@ -449,20 +436,6 @@
         }
 
         /**
-         * Sets whether this key must be invalidated (permanently) once a new fingerprint is
-         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
-         * protecting access to the key.
-         *
-         * <p>By default, enrolling a new fingerprint does not invalidate the key.
-         *
-         * @see #setUserAuthenticators(Set)
-         */
-        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
-            mInvalidatedOnNewFingerprintEnrolled = invalidated;
-            return this;
-        }
-
-        /**
          * Builds a new instance instance of {@code KeyGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing or violates a constraint.
@@ -479,9 +452,8 @@
                     mEncryptionPaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
-                    mUserAuthenticators,
-                    mUserAuthenticationValidityDurationSeconds,
-                    mInvalidatedOnNewFingerprintEnrolled);
+                    mUserAuthenticationRequired,
+                    mUserAuthenticationValidityDurationSeconds);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 5e5cf37..d6d3789 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -95,12 +95,10 @@
 
     private final boolean mRandomizedEncryptionRequired;
 
-    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+    private final boolean mUserAuthenticationRequired;
 
     private final int mUserAuthenticationValidityDurationSeconds;
 
-    private final boolean mInvalidatedOnNewFingerprintEnrolled;
-
     /**
      * Parameter specification for the "{@code AndroidKeyPairGenerator}"
      * instance of the {@link java.security.KeyPairGenerator} API. The
@@ -145,9 +143,8 @@
             String[] signaturePaddings,
             String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
-            int userAuthenticationValidityDurationSeconds,
-            boolean invalidatedOnNewFingerprintEnrolled) {
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -195,9 +192,8 @@
         mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
         mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticators = userAuthenticators;
+        mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -227,9 +223,8 @@
                 null, // signature paddings
                 null, // block modes
                 false, // randomized encryption required
-                0, // user authenticators
-                -1, // user authentication validity duration (seconds)
-                false // invalidate on new fingerprint enrolled
+                false, // user authentication required
+                -1 // user authentication validity duration (seconds)
                 );
     }
 
@@ -396,44 +391,34 @@
     }
 
     /**
-     * Gets the set of user authenticators which protect access to the private key. The key can only
-     * be used iff the user has authenticated to at least one of these user authenticators.
+     * Returns {@code true} if user authentication is required for this key to be used.
      *
      * <p>This restriction applies only to private key operations. Public key operations are not
      * restricted.
      *
-     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     * @see #getUserAuthenticationValidityDurationSeconds()
      */
-    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
-        return mUserAuthenticators;
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
     }
 
     /**
      * Gets the duration of time (seconds) for which the private key can be used after the user
-     * successfully authenticates to one of the associated user authenticators.
+     * is successfully authenticated.
      *
      * <p>This restriction applies only to private key operations. Public key operations are not
      * restricted.
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
+     *
+     * @see #isUserAuthenticationRequired()
      */
     public int getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
     }
 
     /**
-     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
-     * enrolled. This constraint only has effect if fingerprint reader is one of the user
-     * authenticators protecting access to this key.
-     *
-     * @see #getUserAuthenticators()
-     */
-    public boolean isInvalidatedOnNewFingerprintEnrolled() {
-        return mInvalidatedOnNewFingerprintEnrolled;
-    }
-
-    /**
      * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
      * This will build a parameter spec for use with the <a href="{@docRoot}
@@ -493,12 +478,10 @@
 
         private boolean mRandomizedEncryptionRequired = true;
 
-        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+        private boolean mUserAuthenticationRequired;
 
         private int mUserAuthenticationValidityDurationSeconds = -1;
 
-        private boolean mInvalidatedOnNewFingerprintEnrolled;
-
         /**
          * Creates a new instance of the {@code Builder} with the given
          * {@code context}. The {@code context} passed in may be used to pop up
@@ -774,28 +757,31 @@
         }
 
         /**
-         * Sets the user authenticators which protect access to this key. The key can only be used
-         * iff the user has authenticated to at least one of these user authenticators.
+         * Sets whether user authentication is required to use this key.
          *
          * <p>By default, the key can be used without user authentication.
          *
+         * <p>When user authentication is required, the user authorizes the use of the key by
+         * authenticating to this Android device using a subset of their secure lock screen
+         * credentials. Different authentication methods are used depending on whether the every
+         * use of the key must be authenticated (as specified by
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
+         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
+         * information</a>.
+         *
          * <p>This restriction applies only to private key operations. Public key operations are not
          * restricted.
          *
-         * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
-         *        without user authentication.
-         *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          */
-        public Builder setUserAuthenticators(
-                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
-            mUserAuthenticators = userAuthenticators;
+        public Builder setUserAuthenticationRequired(boolean required) {
+            mUserAuthenticationRequired = required;
             return this;
         }
 
         /**
-         * Sets the duration of time (seconds) for which this key can be used after the user
-         * successfully authenticates to one of the associated user authenticators.
+         * Sets the duration of time (seconds) for which this key can be used after the user is
+         * successfully authenticated. This has effect only if user authentication is required.
          *
          * <p>By default, the user needs to authenticate for every use of the key.
          *
@@ -805,7 +791,7 @@
          * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
          *        every use of the key.
          *
-         * @see #setUserAuthenticators(int)
+         * @see #setUserAuthenticationRequired(boolean)
          */
         public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
             mUserAuthenticationValidityDurationSeconds = seconds;
@@ -813,20 +799,6 @@
         }
 
         /**
-         * Sets whether this key must be invalidated (permanently) once a new fingerprint is
-         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
-         * protecting access to the key.
-         *
-         * <p>By default, enrolling a new fingerprint does not invalidate the key.
-         *
-         * @see #setUserAuthenticators(Set)
-         */
-        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
-            mInvalidatedOnNewFingerprintEnrolled = invalidated;
-            return this;
-        }
-
-        /**
          * Builds the instance of the {@code KeyPairGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -852,9 +824,8 @@
                     mSignaturePaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
-                    mUserAuthenticators,
-                    mUserAuthenticationValidityDurationSeconds,
-                    mInvalidatedOnNewFingerprintEnrolled);
+                    mUserAuthenticationRequired,
+                    mUserAuthenticationValidityDurationSeconds);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/KeyPermanentlyInvalidatedException.java
new file mode 100644
index 0000000..229eab0
--- /dev/null
+++ b/keystore/java/android/security/KeyPermanentlyInvalidatedException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.InvalidKeyException;
+
+/**
+ * Indicates that the key can no longer be used because it has been permanently invalidated.
+ *
+ * <p>This can currently occur only for keys that require user authentication. Such keys are
+ * permanently invalidated once the secure lock screen is disabled (i.e., reconfigured to None,
+ * Swipe or other mode which does not authenticate the user) or when the secure lock screen is
+ * forcibly reset (e.g., by Device Admin). Additionally, keys configured to require user
+ * authentication for every use of the key are also permanently invalidated once a new fingerprint
+ * is enrolled or once no more fingerprints are enrolled.
+ */
+public class KeyPermanentlyInvalidatedException extends InvalidKeyException {
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} without detail message and cause.
+     */
+    public KeyPermanentlyInvalidatedException() {
+        super("Key permanently invalidated");
+    }
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
+     * and no cause.
+     */
+    public KeyPermanentlyInvalidatedException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
+     * and cause.
+     */
+    public KeyPermanentlyInvalidatedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 8c49ff0..82d328b 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,8 +16,12 @@
 
 package android.security;
 
+import android.app.ActivityThread;
+import android.app.Application;
 import com.android.org.conscrypt.NativeConstants;
 
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,6 +35,7 @@
 import android.util.Log;
 
 import java.security.InvalidKeyException;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -53,6 +58,14 @@
     public static final int UNDEFINED_ACTION = 9;
     public static final int WRONG_PASSWORD = 10;
 
+    /**
+     * Per operation authentication is needed before this operation is valid.
+     * This is returned from {@link #begin} when begin succeeds but the operation uses
+     * per-operation authentication and must authenticate before calling {@link #update} or
+     * {@link #finish}.
+     */
+    public static final int OP_AUTH_NEEDED = 15;
+
     // Used for UID field to indicate the calling UID.
     public static final int UID_SELF = -1;
 
@@ -66,11 +79,27 @@
     private int mError = NO_ERROR;
 
     private final IKeystoreService mBinder;
+    private final Context mContext;
 
     private IBinder mToken;
 
     private KeyStore(IKeystoreService binder) {
         mBinder = binder;
+        mContext = getContext();
+    }
+
+    private static Context getContext() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread == null) {
+            throw new IllegalStateException(
+                    "Failed to obtain application Context: no ActivityThread");
+        }
+        Application application = activityThread.getApplication();
+        if (application == null) {
+            throw new IllegalStateException(
+                    "Failed to obtain application Context: no Application");
+        }
+        return application;
     }
 
     public static KeyStore getInstance() {
@@ -482,7 +511,8 @@
     /**
      * Check if the operation referenced by {@code token} is currently authorized.
      *
-     * @param token An operation token returned by a call to {@link KeyStore.begin}.
+     * @param token An operation token returned by a call to
+     * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
      */
     public boolean isOperationAuthorized(IBinder token) {
         try {
@@ -531,6 +561,8 @@
                     return new KeyStoreException(errorCode, "Key not found");
                 case VALUE_CORRUPTED:
                     return new KeyStoreException(errorCode, "Key blob corrupted");
+                case OP_AUTH_NEEDED:
+                    return new KeyStoreException(errorCode, "Operation requires authorization");
                 default:
                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
             }
@@ -553,27 +585,76 @@
      * Returns an {@link InvalidKeyException} corresponding to the provided
      * {@link KeyStoreException}.
      */
-    static InvalidKeyException getInvalidKeyException(KeyStoreException e) {
+    InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, KeyStoreException e) {
         switch (e.getErrorCode()) {
             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
                 return new KeyExpiredException();
             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
                 return new KeyNotYetValidException();
             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
-                return new UserNotAuthenticatedException();
-            // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
-            // case KeymasterDefs.KM_ERROR_TBD
-            //     return new NewFingerprintEnrolledException();
+            case OP_AUTH_NEEDED:
+            {
+                // We now need to determine whether the key/operation can become usable if user
+                // authentication is performed, or whether it can never become usable again.
+                // User authentication requirements are contained in the key's characteristics. We
+                // need to check whether these requirements can be be satisfied by asking the user
+                // to authenticate.
+                KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+                int getKeyCharacteristicsErrorCode =
+                        getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
+                if (getKeyCharacteristicsErrorCode != NO_ERROR) {
+                    return new InvalidKeyException(
+                            "Failed to obtained key characteristics",
+                            getKeyStoreException(getKeyCharacteristicsErrorCode));
+                }
+                List<Long> keySids =
+                        keyCharacteristics.getLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
+                if (keySids.isEmpty()) {
+                    // Key is not bound to any SIDs -- no amount of authentication will help here.
+                    return new KeyPermanentlyInvalidatedException();
+                }
+                long rootSid = GateKeeper.getSecureUserId();
+                if ((rootSid != 0) && (keySids.contains(Long.valueOf(rootSid)))) {
+                    // One of the key's SIDs is the current root SID -- user can be authenticated
+                    // against that SID.
+                    return new UserNotAuthenticatedException();
+                }
+
+                long fingerprintOnlySid = getFingerprintOnlySid();
+                if ((fingerprintOnlySid != 0)
+                        && (keySids.contains(Long.valueOf(fingerprintOnlySid)))) {
+                    // One of the key's SIDs is the current fingerprint SID -- user can be
+                    // authenticated against that SID.
+                    return new UserNotAuthenticatedException();
+                }
+
+                // None of the key's SIDs can ever be authenticated
+                return new KeyPermanentlyInvalidatedException();
+            }
             default:
                 return new InvalidKeyException("Keystore operation failed", e);
         }
     }
 
+    private long getFingerprintOnlySid() {
+        FingerprintManager fingerprintManager =
+                mContext.getSystemService(FingerprintManager.class);
+        if (fingerprintManager == null) {
+            return 0;
+        }
+
+        if (!fingerprintManager.isHardwareDetected()) {
+            return 0;
+        }
+
+        return fingerprintManager.getAuthenticatorId();
+    }
+
     /**
      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
      * code.
      */
-    static InvalidKeyException getInvalidKeyException(int errorCode) {
-        return getInvalidKeyException(getKeyStoreException(errorCode));
+    InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
+        return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
     }
 }
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 3b13e83..20dd524 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -22,6 +22,7 @@
 import android.security.keymaster.OperationResult;
 
 import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
@@ -298,19 +299,30 @@
         mAdditionalEntropyForBegin = null;
         if (opResult == null) {
             throw new KeyStoreConnectException();
-        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            switch (opResult.resultCode) {
-                case KeymasterDefs.KM_ERROR_INVALID_NONCE:
-                    throw new InvalidAlgorithmParameterException("Invalid IV");
-            }
-            throw KeyStore.getInvalidKeyException(opResult.resultCode);
         }
 
-        if (opResult.token == null) {
-            throw new IllegalStateException("Keystore returned null operation token");
-        }
+        // Store operation token and handle regardless of the error code returned by KeyStore to
+        // ensure that the operation gets aborted immediately if the code below throws an exception.
         mOperationToken = opResult.token;
         mOperationHandle = opResult.operationHandle;
+
+        // If necessary, throw an exception due to KeyStore operation having failed.
+        GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
+                mKeyStore, mKey, opResult.resultCode);
+        if (e != null) {
+            if (e instanceof InvalidKeyException) {
+                throw (InvalidKeyException) e;
+            } else if (e instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException) e;
+            } else {
+                throw new RuntimeException("Unexpected exception type", e);
+            }
+        }
+
+        if (mOperationToken == null) {
+            throw new IllegalStateException("Keystore returned null operation token");
+        }
+
         loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
         mFirstOperationInitiated = true;
         mIvHasBeenUsed = true;
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java
new file mode 100644
index 0000000..e5933ad
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.security.keymaster.KeymasterDefs;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+
+/**
+ * Assorted utility methods for implementing crypto operations on top of KeyStore.
+ *
+ * @hide
+ */
+abstract class KeyStoreCryptoOperationUtils {
+    private KeyStoreCryptoOperationUtils() {}
+
+    /**
+     * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
+     * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
+     * the {@code init} method should succeed.
+     */
+    static InvalidKeyException getInvalidKeyExceptionForInit(
+            KeyStore keyStore, KeyStoreKey key, int beginOpResultCode) {
+        if (beginOpResultCode == KeyStore.NO_ERROR) {
+            return null;
+        }
+
+        // An error occured. However, some errors should not lead to init throwing an exception.
+        // See below.
+        InvalidKeyException e =
+                keyStore.getInvalidKeyException(key.getAlias(), beginOpResultCode);
+        switch (beginOpResultCode) {
+            case KeyStore.OP_AUTH_NEEDED:
+                // Operation needs to be authorized by authenticating the user. Don't throw an
+                // exception is such authentication is possible for this key
+                // (UserNotAuthenticatedException). An example of when it's not possible is where
+                // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
+                if (e instanceof UserNotAuthenticatedException) {
+                    return null;
+                }
+                break;
+        }
+        return e;
+    }
+
+    /**
+     * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
+     * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
+     * should succeed.
+     */
+    static GeneralSecurityException getExceptionForCipherInit(
+            KeyStore keyStore, KeyStoreKey key, int beginOpResultCode) {
+        if (beginOpResultCode == KeyStore.NO_ERROR) {
+            return null;
+        }
+
+        // Cipher-specific cases
+        switch (beginOpResultCode) {
+            case KeymasterDefs.KM_ERROR_INVALID_NONCE:
+                return new InvalidAlgorithmParameterException("Invalid IV");
+            case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
+                return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
+        }
+
+        // General cases
+        return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index 175369c..e993b50 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -67,7 +67,7 @@
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
     private final int mKeymasterDigest;
-    private final int mMacSizeBytes;
+    private final int mMacSizeBits;
 
     // Fields below are populated by engineInit and should be preserved after engineDoFinal.
     private KeyStoreSecretKey mKey;
@@ -79,12 +79,12 @@
 
     protected KeyStoreHmacSpi(int keymasterDigest) {
         mKeymasterDigest = keymasterDigest;
-        mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
+        mMacSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
     }
 
     @Override
     protected int engineGetMacLength() {
-        return mMacSizeBytes;
+        return (mMacSizeBits + 7) / 8;
     }
 
     @Override
@@ -158,24 +158,36 @@
         KeymasterArguments keymasterArgs = new KeymasterArguments();
         keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
         keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mMacSizeBits);
 
+        KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
         OperationResult opResult = mKeyStore.begin(
                 mKey.getAlias(),
                 KeymasterDefs.KM_PURPOSE_SIGN,
                 true,
                 keymasterArgs,
-                null,
-                new KeymasterArguments());
+                null, // no additional entropy needed for HMAC because it's deterministic
+                keymasterOutputArgs);
         if (opResult == null) {
             throw new KeyStoreConnectException();
-        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getInvalidKeyException(opResult.resultCode);
         }
-        if (opResult.token == null) {
-            throw new IllegalStateException("Keystore returned null operation token");
-        }
+
+        // Store operation token and handle regardless of the error code returned by KeyStore to
+        // ensure that the operation gets aborted immediately if the code below throws an exception.
         mOperationToken = opResult.token;
         mOperationHandle = opResult.operationHandle;
+
+        // If necessary, throw an exception due to KeyStore operation having failed.
+        InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
+                mKeyStore, mKey, opResult.resultCode);
+        if (e != null) {
+            throw e;
+        }
+
+        if (mOperationToken == null) {
+            throw new IllegalStateException("Keystore returned null operation token");
+        }
+
         mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
                 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
                         mKeyStore, mOperationToken));
diff --git a/keystore/java/android/security/KeyStoreKey.java b/keystore/java/android/security/KeyStoreKey.java
new file mode 100644
index 0000000..7a34829
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKey.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.Key;
+
+/**
+ * {@link Key} backed by AndroidKeyStore.
+ *
+ * @hide
+ */
+public class KeyStoreKey implements Key {
+    private final String mAlias;
+    private final String mAlgorithm;
+
+    public KeyStoreKey(String alias, String algorithm) {
+        mAlias = alias;
+        mAlgorithm = algorithm;
+    }
+
+    String getAlias() {
+        return mAlias;
+    }
+
+    @Override
+    public String getAlgorithm() {
+        return mAlgorithm;
+    }
+
+    @Override
+    public String getFormat() {
+        // This key does not export its key material
+        return null;
+    }
+
+    @Override
+    public byte[] getEncoded() {
+        // This key does not export its key material
+        return null;
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index 293c4c9..68b5751 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -45,7 +45,7 @@
         protected HmacBase(int keymasterDigest) {
             super(KeymasterDefs.KM_ALGORITHM_HMAC,
                     keymasterDigest,
-                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
+                    KeymasterUtils.getDigestOutputSizeBits(keymasterDigest));
         }
     }
 
@@ -120,13 +120,6 @@
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
         if (mKeymasterDigest != -1) {
             args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-            int digestOutputSizeBytes =
-                    KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
-            if (digestOutputSizeBytes != -1) {
-                // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
-                // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
-                args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
-            }
         }
         if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
             if (mKeymasterDigest == -1) {
@@ -161,27 +154,10 @@
                 KeymasterDefs.KM_TAG_PADDING,
                 KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
                         spec.getEncryptionPaddings()));
-        if (spec.getUserAuthenticators() == 0) {
-            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        } else {
-            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
-                            spec.getUserAuthenticators()));
-            long secureUserId = GateKeeper.getSecureUserId();
-            if (secureUserId == 0) {
-                throw new IllegalStateException("Secure lock screen must be enabled"
-                        + " to generate keys requiring user authentication");
-            }
-            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, secureUserId);
-        }
-        if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
-            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
-            // that.
-        }
-        if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
-            args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
-                    spec.getUserAuthenticationValidityDurationSeconds());
-        }
+        KeymasterUtils.addUserAuthArgs(args,
+                spec.getContext(),
+                spec.isUserAuthenticationRequired(),
+                spec.getUserAuthenticationValidityDurationSeconds());
         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                 (spec.getKeyValidityStart() != null)
                 ? spec.getKeyValidityStart() : new Date(0));
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
index 206103f..b85ec53 100644
--- a/keystore/java/android/security/KeyStoreKeyProperties.java
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -122,101 +122,6 @@
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {UserAuthenticator.LOCK_SCREEN, UserAuthenticator.FINGERPRINT_READER})
-    public @interface UserAuthenticatorEnum {}
-
-    /**
-     * User authenticators which can be used to restrict/protect access to keys.
-     */
-    public static abstract class UserAuthenticator {
-        private UserAuthenticator() {}
-
-        /** Lock screen. */
-        public static final int LOCK_SCREEN = 1 << 0;
-
-        /** Fingerprint reader/sensor. */
-        public static final int FINGERPRINT_READER = 1 << 1;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return KeymasterDefs.HW_AUTH_PASSWORD;
-                case FINGERPRINT_READER:
-                    return KeymasterDefs.HW_AUTH_FINGERPRINT;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
-            switch (userAuthenticator) {
-                case KeymasterDefs.HW_AUTH_PASSWORD:
-                    return LOCK_SCREEN;
-                case KeymasterDefs.HW_AUTH_FINGERPRINT:
-                    return FINGERPRINT_READER;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
-            int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= toKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
-            @UserAuthenticatorEnum int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= fromKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return "LOCK_SCREEN";
-                case FINGERPRINT_READER:
-                    return "FINGERPRINT_READER";
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
     @IntDef({Origin.GENERATED, Origin.IMPORTED, Origin.UNKNOWN})
     public @interface OriginEnum {}
 
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index a89e4dd..96d58d8 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -36,10 +36,9 @@
     private final String[] mSignaturePaddings;
     private final String[] mDigests;
     private final String[] mBlockModes;
-    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
-    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
+    private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mInvalidatedOnNewFingerprintEnrolled;
+    private final boolean mUserAuthenticationRequirementTeeEnforced;
 
     /**
      * @hide
@@ -56,10 +55,9 @@
             String[] signaturePaddings,
             String[] digests,
             String[] blockModes,
-            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
-            @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
+            boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean invalidatedOnNewFingerprintEnrolled) {
+            boolean userAuthenticationRequirementTeeEnforced) {
         mKeystoreAlias = keystoreKeyAlias;
         mTeeBacked = teeBacked;
         mOrigin = origin;
@@ -74,10 +72,9 @@
                 ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
         mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
         mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
-        mUserAuthenticators = userAuthenticators;
-        mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
+        mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
+        mUserAuthenticationRequirementTeeEnforced = userAuthenticationRequirementTeeEnforced;
     }
 
     /**
@@ -172,43 +169,34 @@
     }
 
     /**
-     * Gets the set of user authenticators which protect access to the key. The key can only be used
-     * iff the user has authenticated to at least one of these user authenticators.
+     * Returns {@code true} if user authentication is required for this key to be used.
      *
-     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     * @see #getUserAuthenticationValidityDurationSeconds()
      */
-    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
-        return mUserAuthenticators;
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
     }
 
     /**
-     * Gets the set of user authenticators for which the TEE enforces access restrictions for this
-     * key. This is a subset of the user authentications returned by
-     * {@link #getUserAuthenticators()}.
-     */
-    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
-        return mTeeEnforcedUserAuthenticators;
-    }
-
-    /**
-     * Gets the duration of time (seconds) for which the key can be used after the user
-     * successfully authenticates to one of the associated user authenticators.
+     * Gets the duration of time (seconds) for which this key can be used after the user is
+     * successfully authenticated.
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
+     *
+     * @see #isUserAuthenticationRequired()
      */
     public int getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
     }
 
     /**
-     * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is
-     * enrolled. This constraint only has effect if fingerprint reader is one of the user
-     * authenticators protecting access to this key.
+     * Returns {@code true} if the requirement that this key can only be used if the user has been
+     * authenticated if enforced by the TEE.
      *
-     * @see #getUserAuthenticators()
+     * @see #isUserAuthenticationRequired()
      */
-    public boolean isInvalidatedOnNewFingerprintEnrolled() {
-        return mInvalidatedOnNewFingerprintEnrolled;
+    public boolean isUserAuthenticationRequirementTeeEnforced() {
+        return mUserAuthenticationRequirementTeeEnforced;
     }
 }
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index c24b74f..b4747e9 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -39,7 +39,8 @@
  * {@code KeyStore}.
  */
 public final class KeyStoreParameter implements ProtectionParameter {
-    private int mFlags;
+    private final Context mContext;
+    private final int mFlags;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
@@ -49,11 +50,12 @@
     private final String[] mDigests;
     private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+    private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
-    private KeyStoreParameter(int flags,
+    private KeyStoreParameter(
+            Context context,
+            int flags,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
@@ -63,15 +65,17 @@
             String[] digests,
             String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
-            int userAuthenticationValidityDurationSeconds,
-            boolean invalidatedOnNewFingerprintEnrolled) {
-        if ((userAuthenticationValidityDurationSeconds < 0)
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
+        if (context == null) {
+            throw new IllegalArgumentException("context == null");
+        } else if ((userAuthenticationValidityDurationSeconds < 0)
                 && (userAuthenticationValidityDurationSeconds != -1)) {
             throw new IllegalArgumentException(
                     "userAuthenticationValidityDurationSeconds must not be negative");
         }
 
+        mContext = context;
         mFlags = flags;
         mKeyValidityStart = keyValidityStart;
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
@@ -84,9 +88,15 @@
         mDigests = ArrayUtils.cloneIfNotEmpty(digests);
         mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticators = userAuthenticators;
+        mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
+     * Gets the Android context used for operations with this instance.
+     */
+    public Context getContext() {
+        return mContext;
     }
 
     /**
@@ -198,18 +208,17 @@
     }
 
     /**
-     * Gets the set of user authenticators which protect access to this key. The key can only be
-     * used iff the user has authenticated to at least one of these user authenticators.
+     * Returns {@code true} if user authentication is required for this key to be used.
      *
-     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     * @see #getUserAuthenticationValidityDurationSeconds()
      */
-    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
-        return mUserAuthenticators;
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
     }
 
     /**
-     * Gets the duration of time (seconds) for which this key can be used after the user
-     * successfully authenticates to one of the associated user authenticators.
+     * Gets the duration of time (seconds) for which this key can be used after the user is
+     * successfully authenticated.
      *
      * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
@@ -219,17 +228,6 @@
     }
 
     /**
-     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
-     * enrolled. This constraint only has effect if fingerprint reader is one of the user
-     * authenticators protecting access to this key.
-     *
-     * @see #getUserAuthenticators()
-     */
-    public boolean isInvalidatedOnNewFingerprintEnrolled() {
-        return mInvalidatedOnNewFingerprintEnrolled;
-    }
-
-    /**
      * Builder class for {@link KeyStoreParameter} objects.
      * <p>
      * This will build protection parameters for use with the
@@ -247,6 +245,7 @@
      * </pre>
      */
     public final static class Builder {
+        private final Context mContext;
         private int mFlags;
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
@@ -257,9 +256,8 @@
         private String[] mDigests;
         private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+        private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
-        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given
@@ -271,8 +269,7 @@
             if (context == null) {
                 throw new NullPointerException("context == null");
             }
-
-            // Context is currently not used, but will be in the future.
+            mContext = context;
         }
 
         /**
@@ -440,32 +437,35 @@
         }
 
         /**
-         * Sets the user authenticators which protect access to this key. The key can only be used
-         * iff the user has authenticated to at least one of these user authenticators.
+         * Sets whether user authentication is required to use this key.
          *
          * <p>By default, the key can be used without user authentication.
          *
-         * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
-         *        without user authentication.
+         * <p>When user authentication is required, the user authorizes the use of the key by
+         * authenticating to this Android device using a subset of their secure lock screen
+         * credentials. Different authentication methods are used depending on whether the every
+         * use of the key must be authenticated (as specified by
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
+         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
+         * information</a>.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          */
-        public Builder setUserAuthenticators(
-                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
-            mUserAuthenticators = userAuthenticators;
+        public Builder setUserAuthenticationRequired(boolean required) {
+            mUserAuthenticationRequired = required;
             return this;
         }
 
         /**
-         * Sets the duration of time (seconds) for which this key can be used after the user
-         * successfully authenticates to one of the associated user authenticators.
+         * Sets the duration of time (seconds) for which this key can be used after the user is
+         * successfully authenticated. This has effect only if user authentication is required.
          *
          * <p>By default, the user needs to authenticate for every use of the key.
          *
          * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
          *        every use of the key.
          *
-         * @see #setUserAuthenticators(int)
+         * @see #setUserAuthenticationRequired(boolean)
          */
         public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
             mUserAuthenticationValidityDurationSeconds = seconds;
@@ -473,27 +473,15 @@
         }
 
         /**
-         * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is
-         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
-         * protecting access to the key.
-         *
-         * <p>By default, enrolling a new fingerprint does not invalidate the key.
-         *
-         * @see #setUserAuthenticators(Set)
-         */
-        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
-            mInvalidatedOnNewFingerprintEnrolled = invalidated;
-            return this;
-        }
-
-        /**
          * Builds the instance of the {@code KeyStoreParameter}.
          *
          * @throws IllegalArgumentException if a required field is missing
          * @return built instance of {@code KeyStoreParameter}
          */
         public KeyStoreParameter build() {
-            return new KeyStoreParameter(mFlags,
+            return new KeyStoreParameter(
+                    mContext,
+                    mFlags,
                     mKeyValidityStart,
                     mKeyValidityForOriginationEnd,
                     mKeyValidityForConsumptionEnd,
@@ -503,9 +491,8 @@
                     mDigests,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
-                    mUserAuthenticators,
-                    mUserAuthenticationValidityDurationSeconds,
-                    mInvalidatedOnNewFingerprintEnrolled);
+                    mUserAuthenticationRequired,
+                    mUserAuthenticationValidityDurationSeconds);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreSecretKey.java b/keystore/java/android/security/KeyStoreSecretKey.java
index 7f0e3d3..ee25465 100644
--- a/keystore/java/android/security/KeyStoreSecretKey.java
+++ b/keystore/java/android/security/KeyStoreSecretKey.java
@@ -23,33 +23,9 @@
  *
  * @hide
  */
-public class KeyStoreSecretKey implements SecretKey {
-    private final String mAlias;
-    private final String mAlgorithm;
+public class KeyStoreSecretKey extends KeyStoreKey implements SecretKey {
 
     public KeyStoreSecretKey(String alias, String algorithm) {
-        mAlias = alias;
-        mAlgorithm = algorithm;
-    }
-
-    String getAlias() {
-        return mAlias;
-    }
-
-    @Override
-    public String getAlgorithm() {
-        return mAlgorithm;
-    }
-
-    @Override
-    public String getFormat() {
-        // This key does not export its key material
-        return null;
-    }
-
-    @Override
-    public byte[] getEncoded() {
-        // This key does not export its key material
-        return null;
+        super(alias, algorithm);
     }
 }
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 4be0638..bfe09e3 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -81,8 +81,8 @@
         String[] encryptionPaddings;
         String[] digests;
         String[] blockModes;
-        @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators;
-        @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
+        int keymasterSwEnforcedUserAuthenticators;
+        int keymasterHwEnforcedUserAuthenticators;
         try {
             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 teeBacked = true;
@@ -122,21 +122,10 @@
                     keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
             blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes(
                     keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
-
-            @KeyStoreKeyProperties.UserAuthenticatorEnum
-            int swEnforcedKeymasterUserAuthenticators =
+            keymasterSwEnforcedUserAuthenticators =
                     keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyProperties.UserAuthenticatorEnum
-            int hwEnforcedKeymasterUserAuthenticators =
+            keymasterHwEnforcedUserAuthenticators =
                     keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyProperties.UserAuthenticatorEnum
-            int keymasterUserAuthenticators =
-                    swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
-            userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
-                    keymasterUserAuthenticators);
-            teeEnforcedUserAuthenticators =
-                    KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
-                            hwEnforcedKeymasterUserAuthenticators);
         } catch (IllegalArgumentException e) {
             throw new InvalidKeySpecException("Unsupported key characteristic", e);
         }
@@ -157,11 +146,13 @@
                 && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
             keyValidityForConsumptionEnd = null;
         }
+        boolean userAuthenticationRequired =
+                !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         int userAuthenticationValidityDurationSeconds =
                 keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
-
-        // TODO: Populate the value below from key characteristics once Keymaster is ready.
-        boolean invalidatedOnNewFingerprintEnrolled = false;
+        boolean userAuthenticationRequirementEnforcedInTee = (userAuthenticationRequired)
+                && (keymasterHwEnforcedUserAuthenticators != 0)
+                && (keymasterSwEnforcedUserAuthenticators == 0);
 
         return new KeyStoreKeySpec(entryAlias,
                 teeBacked,
@@ -175,10 +166,9 @@
                 EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
                 digests,
                 blockModes,
-                userAuthenticators,
-                teeEnforcedUserAuthenticators,
+                userAuthenticationRequired,
                 userAuthenticationValidityDurationSeconds,
-                invalidatedOnNewFingerprintEnrolled);
+                userAuthenticationRequirementEnforcedInTee);
     }
 
     @Override
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 67f75c2..aa44ecd 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,6 +16,9 @@
 
 package android.security;
 
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 
 import libcore.util.EmptyArray;
@@ -176,22 +179,22 @@
         return result;
     }
 
-    public static int getDigestOutputSizeBytes(int keymasterDigest) {
+    public static int getDigestOutputSizeBits(int keymasterDigest) {
         switch (keymasterDigest) {
             case KeymasterDefs.KM_DIGEST_NONE:
                 return -1;
             case KeymasterDefs.KM_DIGEST_MD5:
-                return 128 / 8;
+                return 128;
             case KeymasterDefs.KM_DIGEST_SHA1:
-                return 160 / 8;
+                return 160;
             case KeymasterDefs.KM_DIGEST_SHA_2_224:
-                return 224 / 8;
+                return 224;
             case KeymasterDefs.KM_DIGEST_SHA_2_256:
-                return 256 / 8;
+                return 256;
             case KeymasterDefs.KM_DIGEST_SHA_2_384:
-                return 384 / 8;
+                return 384;
             case KeymasterDefs.KM_DIGEST_SHA_2_512:
-                return 512 / 8;
+                return 512;
             default:
                 throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
         }
@@ -339,4 +342,58 @@
         }
         return result;
     }
+
+    /**
+     * Adds keymaster arguments to express the key's authorization policy supported by user
+     * authentication.
+     *
+     * @param userAuthenticationRequired whether user authentication is required to authorize the
+     *        use of the key.
+     * @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user
+     *        authentication is valid as authorization for using the key or {@code -1} if every
+     *        use of the key needs authorization.
+     */
+    public static void addUserAuthArgs(KeymasterArguments args,
+            Context context,
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
+        if (!userAuthenticationRequired) {
+            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+            return;
+        }
+
+        if (userAuthenticationValidityDurationSeconds == -1) {
+            // Every use of this key needs to be authorized by the user. This currently means
+            // fingerprint-only auth.
+            FingerprintManager fingerprintManager =
+                    context.getSystemService(FingerprintManager.class);
+            if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) {
+                throw new IllegalStateException(
+                        "This device does not support keys which require authentication for every"
+                        + " use -- this requires fingerprint authentication which is not"
+                        + " available on this device");
+            }
+            long fingerprintOnlySid = fingerprintManager.getAuthenticatorId();
+            if (fingerprintOnlySid == 0) {
+                throw new IllegalStateException(
+                        "At least one fingerprint must be enrolled to create keys requiring user"
+                        + " authentication for every use");
+            }
+            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, fingerprintOnlySid);
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+        } else {
+            // The key is authorized for use for the specified amount of time after the user has
+            // authenticated. Whatever unlocks the secure lock screen should authorize this key.
+            long rootSid = GateKeeper.getSecureUserId();
+            if (rootSid == 0) {
+                throw new IllegalStateException("Secure lock screen must be enabled"
+                        + " to create keys requiring user authentication");
+            }
+            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, rootSid);
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
+            args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
+                    userAuthenticationValidityDurationSeconds);
+        }
+    }
 }
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
deleted file mode 100644
index 4fe210b..0000000
--- a/keystore/java/android/security/NewFingerprintEnrolledException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import java.security.InvalidKeyException;
-
-/**
- * Indicates that a cryptographic operation could not be performed because the key used by the
- * operation is permanently invalid because a new fingerprint was enrolled.
- */
-public class NewFingerprintEnrolledException extends InvalidKeyException {
-
-    /**
-     * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
-     */
-    public NewFingerprintEnrolledException() {
-        super("Invalid key: new fingerprint enrolled");
-    }
-
-    /**
-     * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
-     * no cause.
-     */
-    public NewFingerprintEnrolledException(String message) {
-        super(message);
-    }
-}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
index 66f4dd8..2954fa7 100644
--- a/keystore/java/android/security/UserNotAuthenticatedException.java
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -20,7 +20,7 @@
 
 /**
  * Indicates that a cryptographic operation could not be performed because the user has not been
- * authenticated recently enough.
+ * authenticated recently enough. Authenticating the user will resolve this issue.
  */
 public class UserNotAuthenticatedException extends InvalidKeyException {
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index c78971a..dd6af03 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -638,8 +638,7 @@
     DEFER_LOGD("--flushing");
     renderer.eventMark("Flush");
 
-    // save and restore (with draw modifiers) so that reordering doesn't affect final state
-    DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
+    // save and restore so that reordering doesn't affect final state
     renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
     if (CC_LIKELY(mAvoidOverdraw)) {
@@ -654,7 +653,6 @@
     replayBatchList(mBatches, renderer, dirty);
 
     renderer.restoreToCount(1);
-    renderer.setDrawModifiers(restoreDrawModifiers);
 
     DEFER_LOGD("--flush complete, returning %x", status);
     clear();
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index f535afb..3d0ca6d 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -61,7 +61,6 @@
     int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
     bool mClipped;
     mat4 mMatrix;
-    DrawModifiers mDrawModifiers;
     float mAlpha;
     const RoundRectClipState* mRoundRectClipState;
 };
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 6b86030..a7784b6 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -88,8 +88,7 @@
 void DisplayListCanvas::resume() {
 }
 
-void DisplayListCanvas::callDrawGLFunction(Functor *functor, Rect& dirty) {
-    // Ignore dirty during recording, it matters only when we replay
+void DisplayListCanvas::callDrawGLFunction(Functor *functor) {
     addDrawOp(new (alloc()) DrawFunctorOp(functor));
     mDisplayListData->functors.add(functor);
 }
@@ -202,12 +201,12 @@
     return mState.clipRegion(region, op);
 }
 
-void DisplayListCanvas::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
+void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) {
     LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
 
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
-    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *mState.currentTransform());
+    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, *mState.currentTransform());
     addRenderNodeOp(op);
 }
 
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index 2b0b6b2..fa4b2b4 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -115,10 +115,10 @@
 // HWUI Canvas draw operations - special
 // ----------------------------------------------------------------------------
     void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
-    void drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
+    void drawRenderNode(RenderNode* renderNode);
 
     // TODO: rename for consistency
-    void callDrawGLFunction(Functor* functor, Rect& dirty);
+    void callDrawGLFunction(Functor* functor);
 
     void setHighContrastText(bool highContrastText) {
         mHighContrastText = highContrastText;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index b5801fc..e9d6ebc 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1398,10 +1398,9 @@
     friend class RenderNode; // grant RenderNode access to info of child
     friend class DisplayListData; // grant DisplayListData access to info of child
 public:
-    DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
+    DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent)
             : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
             , mRenderNode(renderNode)
-            , mFlags(flags)
             , mTransformFromParent(transformFromParent)
             , mSkipInOrderDraw(false) {}
 
@@ -1424,7 +1423,7 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
-        OP_LOG("Draw RenderNode %p %s, flags %#x", mRenderNode, mRenderNode->getName(), mFlags);
+        OP_LOG("Draw RenderNode %p %s", mRenderNode, mRenderNode->getName());
         if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
             mRenderNode->output(level + 1);
         }
@@ -1436,7 +1435,6 @@
 
 private:
     RenderNode* mRenderNode;
-    const int mFlags;
 
     ///////////////////////////
     // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 65daf03..c8189b8 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -53,6 +53,7 @@
     kWindowLayoutChanged = 1 << 0,
     kRTAnimation = 1 << 1,
     kSurfaceCanvas = 1 << 2,
+    kSkippedFrame = 1 << 3,
 };
 MAKE_FLAGS_ENUM(FrameInfoFlags)
 
@@ -101,6 +102,10 @@
         set(FrameInfoIndex::kFrameCompleted) = systemTime(CLOCK_MONOTONIC);
     }
 
+    void addFlag(FrameInfoFlags flag) {
+        set(FrameInfoIndex::kFlags) |= static_cast<uint64_t>(flag);
+    }
+
     int64_t operator[](FrameInfoIndex index) const {
         if (index == FrameInfoIndex::kNumIndexes) return 0;
         return mFrameInfo[static_cast<int>(index)];
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 30935d5..7fc31b8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -76,9 +76,6 @@
         , mLightRadius(FLT_MIN)
         , mAmbientShadowAlpha(0)
         , mSpotShadowAlpha(0) {
-    // *set* draw modifiers to be 0
-    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
-    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -1188,10 +1185,9 @@
         state.mClip.set(currentClip);
     }
 
-    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
+    // Transform and alpha always deferred, since they are used by state operations
     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
     state.mMatrix.load(*currentMatrix);
-    state.mDrawModifiers = mDrawModifiers;
     state.mAlpha = currentSnapshot()->alpha;
 
     // always store/restore, since it's just a pointer
@@ -1202,7 +1198,6 @@
 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
     setMatrix(state.mMatrix);
     writableSnapshot()->alpha = state.mAlpha;
-    mDrawModifiers = state.mDrawModifiers;
     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
 
     if (state.mClipValid && !skipClipRestore) {
@@ -1262,7 +1257,7 @@
         endTiling();
 
         RenderBuffer* buffer = mCaches.renderBufferCache.get(
-                Stencil::getSmallestStencilFormat(),
+                Stencil::getLayerStencilFormat(),
                 layer->getWidth(), layer->getHeight());
         layer->setStencilRenderBuffer(buffer);
 
@@ -2541,21 +2536,11 @@
 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
         SkXfermode::Mode* mode) const {
     getAlphaAndModeDirect(paint, alpha,  mode);
-    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
-        // if drawing a layer, ignore the paint's alpha
-        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
-    }
     *alpha *= currentSnapshot()->alpha;
 }
 
 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
-    float alpha;
-    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
-        alpha = mDrawModifiers.mOverrideLayerAlpha;
-    } else {
-        alpha = layer->getAlpha() / 255.0f;
-    }
-    return alpha * currentSnapshot()->alpha;
+    return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5f8960a..c34eb2c 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -68,17 +68,6 @@
 class TextDrawFunctor;
 class VertexBuffer;
 
-struct DrawModifiers {
-    DrawModifiers()
-        : mOverrideLayerAlpha(0.0f) {}
-
-    void reset() {
-        mOverrideLayerAlpha = 0.0f;
-    }
-
-    float mOverrideLayerAlpha;
-};
-
 enum StateDeferFlags {
     kStateDeferFlag_Draw = 0x1,
     kStateDeferFlag_Clip = 0x2
@@ -236,9 +225,6 @@
 
     void setDrawFilter(SkDrawFilter* filter);
 
-    // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
-    void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
-
     /**
      * Store the current display state (most importantly, the current clip and transform), and
      * additionally map the state's bounds from local to window coordinates.
@@ -249,9 +235,6 @@
     void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
     void setupMergedMultiDraw(const Rect* clipRect);
 
-    const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
-    void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
-
     bool isCurrentTransformSimple() {
         return currentTransform()->isSimple();
     }
@@ -523,8 +506,7 @@
 
     /**
      * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for both
-     * snapshot alpha, and overrideLayerAlpha
+     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for snapshot alpha.
      *
      * @param paint The paint to extract values from
      * @param alpha Where to store the resulting alpha
@@ -533,7 +515,7 @@
     inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const;
 
     /**
-     * Gets the alpha from a layer, accounting for snapshot alpha and overrideLayerAlpha
+     * Gets the alpha from a layer, accounting for snapshot alpha
      *
      * @param layer The layer from which the alpha is extracted
      */
@@ -868,10 +850,6 @@
     // Default UV mapper
     const UvMapper mUvMapper;
 
-    // shader, filters, and shadow
-    DrawModifiers mDrawModifiers;
-    SkPaint mFilteredPaint;
-
     // List of rectangles to clear after saveLayer() is invoked
     std::vector<Rect> mLayers;
     // List of layers to update at the beginning of a frame
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index ac4c0d0..8f95e0d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -389,12 +389,9 @@
     if (properties().getAlpha() < 1) {
         if (isLayer) {
             clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-
-            renderer.setOverrideLayerAlpha(properties().getAlpha());
-        } else {
-            LOG_ALWAYS_FATAL_IF(properties().getHasOverlappingRendering());
-            renderer.scaleAlpha(properties().getAlpha());
         }
+        LOG_ALWAYS_FATAL_IF(!isLayer && properties().getHasOverlappingRendering());
+        renderer.scaleAlpha(properties().getAlpha());
     }
     if (clipFlags) {
         Rect clipRect;
@@ -902,7 +899,6 @@
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
     handler(new (alloc) RestoreToCountOp(restoreTo),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
-    renderer.setOverrideLayerAlpha(1.0f);
 
     DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
     handler.endMark();
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 0ed3c47..7b75690 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -149,12 +149,10 @@
     if (mPrimitiveFields.mAlpha < 1) {
         if (isLayer) {
             clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-
-            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
-        } else {
-            LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mHasOverlappingRendering);
-            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         }
+
+        LOG_ALWAYS_FATAL_IF(!isLayer && mPrimitiveFields.mHasOverlappingRendering);
+        ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
     }
     if (clipFlags) {
         Rect clipRect;
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index cedb233..92a057d 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -42,12 +42,17 @@
     return STENCIL_BUFFER_SIZE;
 }
 
-GLenum Stencil::getSmallestStencilFormat() {
+/**
+ * This method will return either GL_STENCIL_INDEX4_OES if supported,
+ * GL_STENCIL_INDEX8 if not.
+ *
+ * Layers can't use a single bit stencil because multi-rect ClipArea needs a high enough
+ * stencil resolution to represent the summation of multiple intersecting rect geometries.
+ */
+GLenum Stencil::getLayerStencilFormat() {
 #if !DEBUG_STENCIL
     const Extensions& extensions = Caches::getInstance().extensions();
-    if (extensions.has1BitStencil()) {
-        return GL_STENCIL_INDEX1_OES;
-    } else if (extensions.has4BitStencil()) {
+    if (extensions.has4BitStencil()) {
         return GL_STENCIL_INDEX4_OES;
     }
 #endif
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
index e4f0f3f..3a8f8eb 100644
--- a/libs/hwui/renderstate/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -42,10 +42,7 @@
      */
     ANDROID_API static uint8_t getStencilSize();
 
-    /**
-     * Returns the smallest stencil format accepted by render buffers.
-     */
-    static GLenum getSmallestStencilFormat();
+    static GLenum getLayerStencilFormat();
 
     /**
      * Clears the stencil buffer.
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9237151..3de3086 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,12 +27,25 @@
 #include "../OpenGLRenderer.h"
 
 #include <algorithm>
+#include <cutils/properties.h>
 #include <private/hwui/DrawGlInfo.h>
 #include <strings.h>
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
 
+#define PROPERTY_SKIP_EMPTY_DAMAGE "debug.hwui.skip_empty_damage"
+
+static bool sInitialized = false;
+static bool sSkipEmptyDamage = true;
+
+static void initGlobals() {
+    if (sInitialized) return;
+    sInitialized = true;
+    sSkipEmptyDamage = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE,
+            sSkipEmptyDamage);
+}
+
 namespace android {
 namespace uirenderer {
 namespace renderthread {
@@ -45,6 +58,9 @@
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
         , mRootRenderNode(rootRenderNode)
         , mJankTracker(thread.timeLord().frameIntervalNanos()) {
+    // Done lazily at first draw instead of at library load to avoid
+    // running pre-zygote fork
+    initGlobals();
     mRenderThread.renderState().registerCanvasContext(this);
     mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
 }
@@ -203,12 +219,17 @@
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawRenderNode called on a context with no canvas or surface!");
 
-    profiler().markPlaybackStart();
-    mCurrentFrameInfo->markIssueDrawCommandsStart();
-
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
 
+    if (dirty.isEmpty() && sSkipEmptyDamage) {
+        mCurrentFrameInfo->addFlag(FrameInfoFlags::kSkippedFrame);
+        return;
+    }
+
+    profiler().markPlaybackStart();
+    mCurrentFrameInfo->markIssueDrawCommandsStart();
+
     EGLint width, height;
     mEglManager.beginFrame(mEglSurface, &width, &height);
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
@@ -277,6 +298,8 @@
     prepareTree(info, frameInfo);
     if (info.out.canDrawThisFrame) {
         draw();
+    } else {
+        mCurrentFrameInfo->addFlag(FrameInfoFlags::kSkippedFrame);
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index cc87241..d15fa39 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -293,11 +293,11 @@
     return (void*) success;
 }
 
-bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
     SETUP_TASK(copyLayerInto);
     args->context = mContext;
     args->layer = layer;
-    args->bitmap = bitmap;
+    args->bitmap = &bitmap;
     return (bool) postAndWait(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 29c6f08..cc475fa 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -83,7 +83,7 @@
 
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API void buildLayer(RenderNode* node);
-    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
     ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
     ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
     ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index 61ad082..62782af 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -111,15 +111,13 @@
 public:
     std::vector< sp<RenderNode> > cards;
     void createContent(int width, int height, DisplayListCanvas* renderer) override {
-        android::uirenderer::Rect DUMMY;
-
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
         for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
             for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
                 sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
-                renderer->drawRenderNode(card.get(), DUMMY, 0);
+                renderer->drawRenderNode(card.get());
                 cards.push_back(card);
             }
         }
@@ -153,13 +151,11 @@
 public:
     sp<RenderNode> card;
     void createContent(int width, int height, DisplayListCanvas* renderer) override {
-        android::uirenderer::Rect DUMMY;
-
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
         card = createCard(40, 40, 200, 200);
-        renderer->drawRenderNode(card.get(), DUMMY, 0);
+        renderer->drawRenderNode(card.get());
 
         renderer->insertReorderBarrier(false);
     }
@@ -202,13 +198,11 @@
 public:
     sp<RenderNode> card;
     void createContent(int width, int height, DisplayListCanvas* renderer) override {
-        android::uirenderer::Rect DUMMY;
-
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
         card = createCard(40, 40, 400, 400);
-        renderer->drawRenderNode(card.get(), DUMMY, 0);
+        renderer->drawRenderNode(card.get());
 
         renderer->insertReorderBarrier(false);
     }
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index df128c9..f13a440 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -140,8 +140,6 @@
 
     /**
      * The state of the GPS receiver contains millisecond ambiguity.
-     *
-     * @hide
      */
     public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
 
@@ -399,8 +397,6 @@
      *
      * @return {@code true} if {@link #getPseudorangeRateInMetersPerSec()} contains a corrected
      *         value, {@code false} if it contains an uncorrected value.
-     *
-     * @hide
      */
     public boolean isPseudorangeRateCorrected() {
         return !isFlagSet(GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE);
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 5b12a61..5c3c710 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -62,23 +62,17 @@
 
     /**
      * The Navigation Message Status is 'unknown'.
-     *
-     * @hide
      */
     public static final short STATUS_UNKNOWN = 0;
 
     /**
      * The Navigation Message was received without any parity error in its navigation words.
-     *
-     * @hide
      */
     public static final short STATUS_PARITY_PASSED = (1<<0);
 
     /**
      * The Navigation Message was received with words that failed parity check, but the receiver was
      * able to correct those words.
-     *
-     * @hide
      */
     public static final short STATUS_PARITY_REBUILT = (1<<1);
 
@@ -220,8 +214,6 @@
 
     /**
      * Gets the Status of the navigation message contained in the object.
-     *
-     * @hide
      */
     public short getStatus() {
         return mStatus;
@@ -229,8 +221,6 @@
 
     /**
      * Sets the status of the navigation message.
-     *
-     * @hide
      */
     public void setStatus(short value) {
         mStatus = value;
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index abb4257..a721923 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -51,5 +51,7 @@
         /** Called when internal ringer mode is evaluated, returns the new external ringer mode */
         int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
                 int ringerModeExternal, VolumePolicy policy);
+
+        boolean canVolumeDownEnterSilent();
     }
 }
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 201a796..d5e6b3e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -26,6 +26,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityThread;
+import android.app.Application;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -378,7 +380,7 @@
         int initResult = native_setup( new WeakReference<AudioRecord>(this),
                 mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
                 mAudioFormat, mNativeBufferSizeInBytes,
-                session);
+                session, getMyOpPackageName());
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing native AudioRecord object.");
             return; // with mState == STATE_UNINITIALIZED
@@ -1321,7 +1323,6 @@
         return native_set_pos_update_period(periodInFrames);
     }
 
-
     //--------------------------------------------------------------------------
     // Explicit Routing
     //--------------------
@@ -1451,7 +1452,7 @@
     private native final int native_setup(Object audiorecord_this,
             Object /*AudioAttributes*/ attributes,
             int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
-            int buffSizeInBytes, int[] sessionId);
+            int buffSizeInBytes, int[] sessionId, String opPackageName);
 
     // TODO remove: implementation calls directly into implementation of native_release()
     private native final void native_finalize();
@@ -1500,4 +1501,14 @@
         Log.e(TAG, msg);
     }
 
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 25e6594..3dae543 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.audiopolicy.AudioMix;
+import android.util.Log;
 
 import java.util.ArrayList;
 
@@ -32,6 +33,7 @@
  */
 public class AudioSystem
 {
+    private static final String TAG = "AudioSystem";
     /* These values must be kept in sync with system/audio.h */
     /*
      * If these are modified, please also update Settings.System.VOLUME_SETTINGS
@@ -224,6 +226,48 @@
         }
     }
 
+    /**
+     * Handles events for the audio policy manager about dynamic audio policies
+     * @see android.media.audiopolicy.AudioPolicy
+     */
+    public interface DynamicPolicyCallback
+    {
+        void onDynamicPolicyMixStateUpdate(String regId, int state);
+    }
+
+    //keep in sync with include/media/AudioPolicy.h
+    private final static int DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE = 0;
+
+    private static DynamicPolicyCallback sDynPolicyCallback;
+
+    public static void setDynamicPolicyCallback(DynamicPolicyCallback cb)
+    {
+        synchronized (AudioSystem.class) {
+            sDynPolicyCallback = cb;
+            native_register_dynamic_policy_callback();
+        }
+    }
+
+    private static void dynamicPolicyCallbackFromNative(int event, String regId, int val)
+    {
+        DynamicPolicyCallback cb = null;
+        synchronized (AudioSystem.class) {
+            if (sDynPolicyCallback != null) {
+                cb = sDynPolicyCallback;
+            }
+        }
+        if (cb != null) {
+            switch(event) {
+                case DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE:
+                    cb.onDynamicPolicyMixStateUpdate(regId, val);
+                    break;
+                default:
+                    Log.e(TAG, "dynamicPolicyCallbackFromNative: unknown event " + event);
+            }
+        }
+    }
+
+
     /*
      * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
      * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
@@ -580,6 +624,9 @@
     public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation);
     public static native int setAudioPortConfig(AudioPortConfig config);
 
+    // declare this instance as having a dynamic policy callback handler
+    private static native final void native_register_dynamic_policy_callback();
+
     // must be kept in sync with value in include/system/audio.h
     public static final int AUDIO_HW_SYNC_INVALID = 0;
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6f1fd24..cb05cc5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -920,13 +920,7 @@
      * @throws IllegalStateException if track is not initialized.
      */
     public @NonNull PlaybackSettings getPlaybackSettings() {
-        float[] floatArray = new float[2];
-        int[] intArray = new int[2];
-        native_get_playback_settings(floatArray, intArray);
-        return new PlaybackSettings()
-                .setSpeed(floatArray[0])
-                .setPitch(floatArray[1])
-                .setAudioFallbackMode(intArray[0]);
+        return native_get_playback_settings();
     }
 
     /**
@@ -1340,21 +1334,7 @@
         if (settings == null) {
             throw new IllegalArgumentException("settings is null");
         }
-        float[] floatArray;
-        int[] intArray;
-        try {
-            floatArray = new float[] {
-                    settings.getSpeed(),
-                    settings.getPitch(),
-            };
-            intArray = new int[] {
-                    settings.getAudioFallbackMode(),
-                    PlaybackSettings.AUDIO_STRETCH_MODE_DEFAULT,
-            };
-        } catch (IllegalStateException e) {
-            throw new IllegalArgumentException(e);
-        }
-        native_set_playback_settings(floatArray, intArray);
+        native_set_playback_settings(settings);
     }
 
 
@@ -2353,14 +2333,8 @@
     private native final int native_set_playback_rate(int sampleRateInHz);
     private native final int native_get_playback_rate();
 
-    // floatArray must be a non-null array of length >= 2
-    // [0] is speed
-    // [1] is pitch
-    // intArray must be a non-null array of length >= 2
-    // [0] is audio fallback mode
-    // [1] is audio stretch mode
-    private native final void native_set_playback_settings(float[] floatArray, int[] intArray);
-    private native final void native_get_playback_settings(float[] floatArray, int[] intArray);
+    private native final void native_set_playback_settings(@NonNull PlaybackSettings settings);
+    private native final @NonNull PlaybackSettings native_get_playback_settings();
 
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index a33fa59..77adb39 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1953,21 +1953,16 @@
 
         TrackInfo(Parcel in) {
             mTrackType = in.readInt();
-            // TODO: parcel in the full MediaFormat
+            // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
+            // even for audio/video tracks, meaning we only set the mime and language.
+            String mime = in.readString();
             String language = in.readString();
+            mFormat = MediaFormat.createSubtitleFormat(mime, language);
 
-            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
-                mFormat = MediaFormat.createSubtitleFormat(
-                    MEDIA_MIMETYPE_TEXT_SUBRIP, language);
-            } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                String mime = in.readString();
-                mFormat = MediaFormat.createSubtitleFormat(mime, language);
+            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
                 mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
                 mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
                 mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
-            } else {
-                mFormat = new MediaFormat();
-                mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
             }
         }
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 78fd9f0..1b054cc 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
+import android.app.Application;
 import android.hardware.Camera;
 import android.os.Handler;
 import android.os.Looper;
@@ -111,7 +112,7 @@
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
-        native_setup(new WeakReference<MediaRecorder>(this), packageName);
+        native_setup(new WeakReference<MediaRecorder>(this), packageName, getMyOpPackageName());
     }
 
     /**
@@ -1080,7 +1081,7 @@
     private static native final void native_init();
 
     private native final void native_setup(Object mediarecorder_this,
-            String clientName) throws IllegalStateException;
+            String clientName, String opPackageName) throws IllegalStateException;
 
     private native final void native_finalize();
 
@@ -1088,4 +1089,15 @@
 
     @Override
     protected void finalize() { native_finalize(); }
+
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
index dc6760d..ecc87e7 100644
--- a/media/java/android/media/MediaSync.java
+++ b/media/java/android/media/MediaSync.java
@@ -199,6 +199,7 @@
     private final Object mAudioLock = new Object();
     private AudioTrack mAudioTrack = null;
     private List<AudioBuffer> mAudioBuffers = new LinkedList<AudioBuffer>();
+    // this is only used for paused/running decisions, so it is not affected by clock drift
     private float mPlaybackRate = 0.0f;
 
     private long mNativeContext;
@@ -459,36 +460,11 @@
      * @throws IllegalArgumentException if the settings are not supported.
      */
     public void setPlaybackSettings(@NonNull PlaybackSettings settings) {
-        float rate;
-        try {
-            rate = settings.getSpeed();
-
-            // rate is specified
-            if (mAudioTrack != null) {
-                try {
-                    if (rate == 0.0) {
-                        mAudioTrack.pause();
-                    } else {
-                        mAudioTrack.setPlaybackSettings(settings);
-                        mAudioTrack.play();
-                    }
-                } catch (IllegalStateException e) {
-                    throw e;
-                }
-            }
-
-            synchronized(mAudioLock) {
-                mPlaybackRate = rate;
-            }
-            if (mPlaybackRate != 0.0 && mAudioThread != null) {
-                postRenderAudio(0);
-            }
-            native_setPlaybackRate(mPlaybackRate);
-        } catch (IllegalStateException e) {
-            // rate is not specified; still, propagate settings to audio track
-            if (mAudioTrack != null) {
-                mAudioTrack.setPlaybackSettings(settings);
-            }
+        synchronized(mAudioLock) {
+            mPlaybackRate = native_setPlaybackSettings(settings);;
+        }
+        if (mPlaybackRate != 0.0 && mAudioThread != null) {
+            postRenderAudio(0);
         }
     }
 
@@ -501,18 +477,9 @@
      *     been initialized.
      */
     @NonNull
-    public PlaybackSettings getPlaybackSettings() {
-        if (mAudioTrack != null) {
-            return mAudioTrack.getPlaybackSettings();
-        } else {
-            PlaybackSettings settings = new PlaybackSettings();
-            settings.allowDefaults();
-            settings.setSpeed(mPlaybackRate);
-            return settings;
-        }
-    }
+    public native PlaybackSettings getPlaybackSettings();
 
-    private native final void native_setPlaybackRate(float rate);
+    private native float native_setPlaybackSettings(@NonNull PlaybackSettings settings);
 
     /**
      * Sets A/V sync mode.
@@ -523,7 +490,16 @@
      * initialized.
      * @throws IllegalArgumentException if settings are not supported.
      */
-    public native void setSyncSettings(@NonNull SyncSettings settings);
+    public void setSyncSettings(@NonNull SyncSettings settings) {
+        synchronized(mAudioLock) {
+            mPlaybackRate = native_setSyncSettings(settings);;
+        }
+        if (mPlaybackRate != 0.0 && mAudioThread != null) {
+            postRenderAudio(0);
+        }
+    }
+
+    private native float native_setSyncSettings(@NonNull SyncSettings settings);
 
     /**
      * Gets the A/V sync mode.
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
index 4e937a5..5add65a 100644
--- a/media/java/android/media/RemoteDisplay.java
+++ b/media/java/android/media/RemoteDisplay.java
@@ -37,17 +37,19 @@
     private final CloseGuard mGuard = CloseGuard.get();
     private final Listener mListener;
     private final Handler mHandler;
+    private final String mOpPackageName;
 
     private long mPtr;
 
-    private native long nativeListen(String iface);
+    private native long nativeListen(String iface, String opPackageName);
     private native void nativeDispose(long ptr);
     private native void nativePause(long ptr);
     private native void nativeResume(long ptr);
 
-    private RemoteDisplay(Listener listener, Handler handler) {
+    private RemoteDisplay(Listener listener, Handler handler, String opPackageName) {
         mListener = listener;
         mHandler = handler;
+        mOpPackageName = opPackageName;
     }
 
     @Override
@@ -66,7 +68,8 @@
      * @param listener The listener to invoke when displays are connected or disconnected.
      * @param handler The handler on which to invoke the listener.
      */
-    public static RemoteDisplay listen(String iface, Listener listener, Handler handler) {
+    public static RemoteDisplay listen(String iface, Listener listener, Handler handler,
+            String opPackageName) {
         if (iface == null) {
             throw new IllegalArgumentException("iface must not be null");
         }
@@ -77,7 +80,7 @@
             throw new IllegalArgumentException("handler must not be null");
         }
 
-        RemoteDisplay display = new RemoteDisplay(listener, handler);
+        RemoteDisplay display = new RemoteDisplay(listener, handler, opPackageName);
         display.startListening(iface);
         return display;
     }
@@ -113,7 +116,7 @@
     }
 
     private void startListening(String iface) {
-        mPtr = nativeListen(iface);
+        mPtr = nativeListen(iface, mOpPackageName);
         if (mPtr == 0) {
             throw new IllegalStateException("Could not start listening for "
                     + "remote display connection on \"" + iface + "\"");
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index a8b9686e..9fc90df 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -18,6 +18,8 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.ActivityThread;
+import android.app.Application;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -395,7 +397,7 @@
         // native initialization
         int initResult = native_setup(new WeakReference<AudioEffect>(this),
                 type.toString(), uuid.toString(), priority, audioSession, id,
-                desc);
+                desc, getMyOpPackageName());
         if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
             Log.e(TAG, "Error code " + initResult
                     + " when initializing AudioEffect.");
@@ -1217,7 +1219,8 @@
     private static native final void native_init();
 
     private native final int native_setup(Object audioeffect_this, String type,
-            String uuid, int priority, int audioSession, int[] id, Object[] desc);
+            String uuid, int priority, int audioSession, int[] id, Object[] desc,
+            String opPackageName);
 
     private native final void native_finalize();
 
@@ -1356,4 +1359,15 @@
         }
         return b;
     }
+
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioEffect outside of an app");
+    }
 }
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 24c74ac..0c48063 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -16,6 +16,8 @@
 
 package android.media.audiofx;
 
+import android.app.ActivityThread;
+import android.app.Application;
 import android.util.Log;
 import java.lang.ref.WeakReference;
 import android.os.Handler;
@@ -206,7 +208,8 @@
         synchronized (mStateLock) {
             mState = STATE_UNINITIALIZED;
             // native initialization
-            int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id);
+            int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id,
+                    getMyOpPackageName());
             if (result != SUCCESS && result != ALREADY_EXISTS) {
                 Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
                 switch (result) {
@@ -716,7 +719,8 @@
 
     private native final int native_setup(Object audioeffect_this,
                                           int audioSession,
-                                          int[] id);
+                                          int[] id,
+                                          String opPackageName);
 
     private native final void native_finalize();
 
@@ -766,5 +770,15 @@
 
     }
 
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
 
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 6aa4d8a..4ffac6d 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -36,20 +36,30 @@
     private int mRouteFlags;
     private String mRegistrationId;
     private int mMixType = MIX_TYPE_INVALID;
-    private int mMixState = MIX_STATE_DISABLED;
+    int mMixState = MIX_STATE_DISABLED;
+    int mCallbackFlags;
 
     /**
      * All parameters are guaranteed valid through the Builder.
      */
-    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags) {
+    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags) {
         mRule = rule;
         mFormat = format;
         mRouteFlags = routeFlags;
         mRegistrationId = null;
         mMixType = rule.getTargetMixType();
+        mCallbackFlags = callbackFlags;
     }
 
-    // ROUTE_FLAG_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
+    // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
+    // in frameworks/av/include/media/AudioPolicy.h
+    /** @hide */
+    public final static int CALLBACK_FLAG_NOTIFY_ACTIVITY = 0x1;
+    // when adding new MIX_FLAG_* flags, add them to this mask of authorized masks:
+    private final static int CALLBACK_FLAGS_ALL = CALLBACK_FLAG_NOTIFY_ACTIVITY;
+
+    // ROUTE_FLAG_* values: keep in sync with MIX_ROUTE_FLAG_* values defined
+    // in frameworks/av/include/media/AudioPolicy.h
     /**
      * An audio mix behavior where the output of the mix is sent to the original destination of
      * the audio signal, i.e. an output device for an output mix, or a recording for an input mix.
@@ -161,6 +171,7 @@
         private AudioMixingRule mRule = null;
         private AudioFormat mFormat = null;
         private int mRouteFlags = 0;
+        private int mCallbackFlags = 0;
 
         /**
          * @hide
@@ -199,6 +210,22 @@
         }
 
         /**
+         * @hide
+         * Only used by AudioPolicyConfig, not a public API.
+         * @param callbackFlags which callbacks are called from native
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public Builder setCallbackFlags(int flags) throws IllegalArgumentException {
+            if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
+                throw new IllegalArgumentException("Illegal callback flags 0x"
+                        + Integer.toHexString(flags).toUpperCase());
+            }
+            mCallbackFlags = flags;
+            return this;
+        }
+
+        /**
          * Sets the {@link AudioFormat} for the mix.
          * @param format a non-null {@link AudioFormat} instance.
          * @return the same Builder instance.
@@ -256,7 +283,7 @@
                 }
                 mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
             }
-            return new AudioMix(mRule, mFormat, mRouteFlags);
+            return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags);
         }
     }
 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index f128044..423b467 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -189,6 +189,12 @@
 
         @SystemApi
         public AudioPolicy build() {
+            if (mStatusListener != null) {
+                // the AudioPolicy status listener includes updates on each mix activity state
+                for (AudioMix mix : mMixes) {
+                    mix.mCallbackFlags |= AudioMix.CALLBACK_FLAG_NOTIFY_ACTIVITY;
+                }
+            }
             return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
                     mFocusListener, mStatusListener);
         }
@@ -432,6 +438,18 @@
                         + afi.getClientId() + "wasNotified=" + wasNotified);
             }
         }
+
+        public void notifyMixStateUpdate(String regId, int state) {
+            for (AudioMix mix : mConfig.getMixes()) {
+                if (mix.getRegistration().equals(regId)) {
+                    mix.mMixState = state;
+                    sendMsg(MSG_MIX_STATE_UPDATE, mix, 0/*ignored*/);
+                    if (DEBUG) {
+                        Log.v(TAG, "notifyMixStateUpdate: regId=" + regId + " state=" + state);
+                    }
+                }
+            }
+        }
     };
 
     //==================================================
@@ -440,6 +458,7 @@
     private final static int MSG_POLICY_STATUS_CHANGE = 0;
     private final static int MSG_FOCUS_GRANT = 1;
     private final static int MSG_FOCUS_LOSS = 2;
+    private final static int MSG_MIX_STATE_UPDATE = 3;
 
     private class EventHandler extends Handler {
         public EventHandler(AudioPolicy ap, Looper looper) {
@@ -464,6 +483,11 @@
                                 (AudioFocusInfo) msg.obj, msg.arg1 != 0);
                     }
                     break;
+                case MSG_MIX_STATE_UPDATE:
+                    if (mStatusListener != null) {
+                        mStatusListener.onMixStateUpdate((AudioMix) msg.obj);
+                    }
+                    break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what);
             }
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 917e07b..252f5f4 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -59,6 +59,10 @@
         mMixes.add(mix);
     }
 
+    public ArrayList<AudioMix> getMixes() {
+        return mMixes;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(mMixes);
@@ -75,6 +79,8 @@
         for (AudioMix mix : mMixes) {
             // write mix route flags
             dest.writeInt(mix.getRouteFlags());
+            // write callback flags
+            dest.writeInt(mix.mCallbackFlags);
             // write mix format
             dest.writeInt(mix.getFormat().getSampleRate());
             dest.writeInt(mix.getFormat().getEncoding());
@@ -96,6 +102,8 @@
             // read mix route flags
             int routeFlags = in.readInt();
             mixBuilder.setRouteFlags(routeFlags);
+            // read callback flags
+            mixBuilder.setCallbackFlags(in.readInt());
             // read mix format
             int sampleRate = in.readInt();
             int encoding = in.readInt();
diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
index c777c58..ad8af15 100644
--- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
+++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
@@ -25,4 +25,7 @@
     // callbacks for audio focus
     void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult);
     void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified);
+
+    // callback for mix activity status update
+    void notifyMixStateUpdate(in String regId, int state);
 }
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index af108eb..35374ed 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -69,6 +69,13 @@
     public static final String PROPERTY_PRODUCT = "product";
 
     /**
+     * Bundle key for the device's version property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     * Matches the USB device version number for USB MIDI devices.
+     */
+    public static final String PROPERTY_VERSION = "version";
+
+    /**
      * Bundle key for the device's serial number property.
      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
      * Matches the USB device serial number for USB MIDI devices.
diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
index d069075..f8799d4 100644
--- a/media/java/android/media/midi/MidiReceiver.java
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -23,6 +23,10 @@
  */
 abstract public class MidiReceiver {
     /**
+     * Although public, this method should be considered a private implementation
+     * detail. Client code should call {@link #send} or {@link #sendWithTimestamp}
+     * instead.
+     *
      * Called to pass MIDI data to the receiver.
      * May fail if count exceeds {@link #getMaxMessageSize}.
      *
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index a3442e3..95aaa7f 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -41,8 +41,9 @@
 public class ITvInputSessionWrapper extends ITvInputSession.Stub implements HandlerCaller.Callback {
     private static final String TAG = "TvInputSessionWrapper";
 
-    private static final int MESSAGE_HANDLING_DURATION_THRESHOLD_MILLIS = 50;
-    private static final int MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS = 2000;
+    private static final int EXECUTE_MESSAGE_TIMEOUT_SHORT_MILLIS = 50;
+    private static final int EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS = 2000;
+    private static final int EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS = 5 * 1000;
 
     private static final int DO_RELEASE = 1;
     private static final int DO_SET_MAIN = 2;
@@ -184,14 +185,18 @@
             }
         }
         long duration = System.currentTimeMillis() - startTime;
-        if (duration > MESSAGE_HANDLING_DURATION_THRESHOLD_MILLIS) {
+        if (duration > EXECUTE_MESSAGE_TIMEOUT_SHORT_MILLIS) {
             Log.w(TAG, "Handling message (" + msg.what + ") took too long time (duration="
                     + duration + "ms)");
-            if (msg.what == DO_TUNE && duration > MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS) {
+            if (msg.what == DO_TUNE && duration > EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS) {
                 throw new RuntimeException("Too much time to handle tune request. (" + duration
-                        + "ms > " + MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS + "ms) "
+                        + "ms > " + EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS + "ms) "
                         + "Consider handling the tune request in a separate thread.");
             }
+            if (duration > EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS) {
+                throw new RuntimeException("Too much time to handle a request. (type=" + msg.what +
+                        ", " + duration + "ms > " + EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS + "ms).");
+            }
         }
     }
 
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 5f586a9..e34f9ed 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -592,8 +592,8 @@
         break;
     }
 
-    // TODO: propagate reason from MediaCodec.
-    int reason = gExceptionReason.reasonHardware;
+    int reason =
+        (err == DEAD_OBJECT) ? gExceptionReason.reasonReclaimed : gExceptionReason.reasonHardware;
     return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get(), reason);
 }
 
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 88a6771..59fb6d6 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -299,15 +299,16 @@
         return NULL;
     }
 
-    SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
 
-    bitmap->lockPixels();
-    rotate((uint16_t*)bitmap->getPixels(),
+    bitmap.lockPixels();
+    rotate((uint16_t*)bitmap.getPixels(),
            (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
            videoFrame->mWidth,
            videoFrame->mHeight,
            videoFrame->mRotationAngle);
-    bitmap->unlockPixels();
+    bitmap.unlockPixels();
 
     if (videoFrame->mDisplayWidth  != videoFrame->mWidth ||
         videoFrame->mDisplayHeight != videoFrame->mHeight) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2c61779..5b55a61 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -174,6 +174,8 @@
     } else {  // Throw exception!
         if ( opStatus == (status_t) INVALID_OPERATION ) {
             jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        } else if ( opStatus == (status_t) BAD_VALUE ) {
+            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
             jniThrowException(env, "java/lang/SecurityException", NULL);
         } else if ( opStatus != (status_t) OK ) {
@@ -442,8 +444,33 @@
             pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
             pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
 
-    // TODO: pass playback settings to mediaplayer when audiotrack supports it
-    process_media_player_call(env, thiz, mp->setPlaybackRate(pbs.audioRate.mSpeed), NULL, NULL);
+    AudioPlaybackRate rate;
+    status_t err = mp->getPlaybackSettings(&rate);
+    if (err == OK) {
+        bool updatedRate = false;
+        if (pbs.speedSet) {
+            rate.mSpeed = pbs.audioRate.mSpeed;
+            updatedRate = true;
+        }
+        if (pbs.pitchSet) {
+            rate.mPitch = pbs.audioRate.mPitch;
+            updatedRate = true;
+        }
+        if (pbs.audioFallbackModeSet) {
+            rate.mFallbackMode = pbs.audioRate.mFallbackMode;
+            updatedRate = true;
+        }
+        if (pbs.audioStretchModeSet) {
+            rate.mStretchMode = pbs.audioRate.mStretchMode;
+            updatedRate = true;
+        }
+        if (updatedRate) {
+            err = mp->setPlaybackSettings(rate);
+        }
+    }
+    process_media_player_call(
+            env, thiz, err,
+            "java/lang/IllegalStateException", "unexpected error");
 }
 
 static jobject
@@ -457,15 +484,9 @@
 
     PlaybackSettings pbs;
     AudioPlaybackRate &audioRate = pbs.audioRate;
-
-    audioRate.mSpeed = 1.0f;
-    audioRate.mPitch = 1.0f;
-    audioRate.mFallbackMode = AUDIO_TIMESTRETCH_FALLBACK_DEFAULT;
-    audioRate.mStretchMode = AUDIO_TIMESTRETCH_STRETCH_DEFAULT;
-
-    // TODO: get this from mediaplayer when audiotrack supports it
-    // process_media_player_call(
-    //        env, thiz, mp->getPlaybackSettings(&audioRate), NULL, NULL);
+    process_media_player_call(
+            env, thiz, mp->getPlaybackSettings(&audioRate),
+            "java/lang/IllegalStateException", "unexpected error");
     ALOGV("getPlaybackSettings: %f %f %d %d",
             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
 
@@ -489,13 +510,35 @@
     SyncSettings scs;
     scs.fillFromJobject(env, gSyncSettingsFields, settings);
     ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f",
-            scs.syncSourceSet, scs.syncSource,
-            scs.audioAdjustModeSet, scs.audioAdjustMode,
-            scs.toleranceSet, scs.tolerance,
-            scs.frameRateSet, scs.frameRate);
+          scs.syncSourceSet, scs.sync.mSource,
+          scs.audioAdjustModeSet, scs.sync.mAudioAdjustMode,
+          scs.toleranceSet, scs.sync.mTolerance,
+          scs.frameRateSet, scs.frameRate);
 
-    // TODO: pass sync settings to mediaplayer when it supports it
-    // process_media_player_call(env, thiz, mp->setSyncSettings(scs), NULL, NULL);
+    AVSyncSettings avsync;
+    float videoFrameRate;
+    status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
+    if (err == OK) {
+        bool updatedSync = scs.frameRateSet;
+        if (scs.syncSourceSet) {
+            avsync.mSource = scs.sync.mSource;
+            updatedSync = true;
+        }
+        if (scs.audioAdjustModeSet) {
+            avsync.mAudioAdjustMode = scs.sync.mAudioAdjustMode;
+            updatedSync = true;
+        }
+        if (scs.toleranceSet) {
+            avsync.mTolerance = scs.sync.mTolerance;
+            updatedSync = true;
+        }
+        if (updatedSync) {
+            err = mp->setSyncSettings(avsync, scs.frameRateSet ? scs.frameRate : -1.f);
+        }
+    }
+    process_media_player_call(
+            env, thiz, err,
+            "java/lang/IllegalStateException", "unexpected error");
 }
 
 static jobject
@@ -508,21 +551,27 @@
     }
 
     SyncSettings scs;
-    scs.syncSource = 0; // SYNC_SOURCE_DEFAULT
-    scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT
-    scs.tolerance = 0.f;
-    scs.frameRate = 0.f;
+    scs.frameRate = -1.f;
+    process_media_player_call(
+            env, thiz, mp->getSyncSettings(&scs.sync, &scs.frameRate),
+            "java/lang/IllegalStateException", "unexpected error");
 
-    // TODO: get this from mediaplayer when it supports it
-    // process_media_player_call(
-    //        env, thiz, mp->getSyncSettings(&scs), NULL, NULL);
     ALOGV("getSyncSettings: %d %d %f %f",
-            scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate);
+            scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
+
+    // sanity check settings
+    if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
+            || scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
+            || scs.sync.mTolerance < 0.f
+            || scs.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
+        jniThrowException(env,  "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
 
     scs.syncSourceSet = true;
     scs.audioAdjustModeSet = true;
     scs.toleranceSet = true;
-    scs.frameRateSet = false;
+    scs.frameRateSet = scs.frameRate >= 0.f;
 
     return scs.asJobject(env, gSyncSettingsFields);
 }
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 8b7d40d..02297fc 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -31,6 +31,8 @@
 #include <media/mediarecorder.h>
 #include <utils/threads.h>
 
+#include <ScopedUtfChars.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -444,11 +446,13 @@
 
 static void
 android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-                                         jstring packageName)
+                                         jstring packageName, jstring opPackageName)
 {
     ALOGV("setup");
 
-    sp<MediaRecorder> mr = new MediaRecorder();
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
+    sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
     if (mr == NULL) {
         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
         return;
@@ -506,7 +510,8 @@
     {"native_reset",         "()V",                             (void *)android_media_MediaRecorder_native_reset},
     {"release",              "()V",                             (void *)android_media_MediaRecorder_release},
     {"native_init",          "()V",                             (void *)android_media_MediaRecorder_native_init},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;)V", (void *)android_media_MediaRecorder_native_setup},
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V",
+                                                                (void *)android_media_MediaRecorder_native_setup},
     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
 };
 
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
index f192262..8ad4b71 100644
--- a/media/jni/android_media_MediaSync.cpp
+++ b/media/jni/android_media_MediaSync.cpp
@@ -21,6 +21,7 @@
 #include "android_media_MediaSync.h"
 
 #include "android_media_AudioTrack.h"
+#include "android_media_PlaybackSettings.h"
 #include "android_media_SyncSettings.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
@@ -29,6 +30,7 @@
 
 #include <gui/Surface.h>
 
+#include <media/AudioResamplerPublic.h>
 #include <media/AudioTrack.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaSync.h>
@@ -47,6 +49,7 @@
 };
 
 static fields_t gFields;
+static PlaybackSettings::fields_t gPlaybackSettingsFields;
 static SyncSettings::fields_t gSyncSettingsFields;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -62,10 +65,8 @@
     return mSync->configureSurface(bufferProducer);
 }
 
-status_t JMediaSync::configureAudioTrack(
-        const sp<AudioTrack> &audioTrack,
-        int32_t nativeSampleRateInHz) {
-    return mSync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+status_t JMediaSync::configureAudioTrack(const sp<AudioTrack> &audioTrack) {
+    return mSync->configureAudioTrack(audioTrack);
 }
 
 status_t JMediaSync::createInputSurface(
@@ -73,14 +74,34 @@
     return mSync->createInputSurface(bufferProducer);
 }
 
-status_t JMediaSync::setPlaybackRate(float rate) {
-    return mSync->setPlaybackRate(rate);
-}
-
 sp<const MediaClock> JMediaSync::getMediaClock() {
     return mSync->getMediaClock();
 }
 
+status_t JMediaSync::setPlaybackSettings(const AudioPlaybackRate& rate) {
+    return mSync->setPlaybackSettings(rate);
+}
+
+void JMediaSync::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
+    mSync->getPlaybackSettings(rate);
+}
+
+status_t JMediaSync::setSyncSettings(const AVSyncSettings& syncSettings) {
+    return mSync->setSyncSettings(syncSettings);
+}
+
+void JMediaSync::getSyncSettings(AVSyncSettings* syncSettings /* nonnull */) {
+    mSync->getSyncSettings(syncSettings);
+}
+
+status_t JMediaSync::setVideoFrameRateHint(float rate) {
+    return mSync->setVideoFrameRateHint(rate);
+}
+
+float JMediaSync::getVideoFrameRate() {
+    return mSync->getVideoFrameRate();
+}
+
 status_t JMediaSync::updateQueuedAudioData(
         int sizeInBytes, int64_t presentationTimeUs) {
     return mSync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
@@ -176,7 +197,7 @@
 }
 
 static void android_media_MediaSync_native_configureAudioTrack(
-        JNIEnv *env, jobject thiz, jobject jaudioTrack, jint nativeSampleRateInHz) {
+        JNIEnv *env, jobject thiz, jobject jaudioTrack) {
     ALOGV("android_media_MediaSync_configureAudioTrack");
 
     sp<JMediaSync> sync = getMediaSync(env, thiz);
@@ -194,7 +215,7 @@
         }
     }
 
-    status_t err = sync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+    status_t err = sync->configureAudioTrack(audioTrack);
 
     if (err == INVALID_OPERATION) {
         throwExceptionAsNecessary(
@@ -287,29 +308,132 @@
     return (jlong)playTimeUs;
 }
 
-static void
-android_media_MediaSync_setSyncSettings(JNIEnv *env, jobject thiz, jobject settings)
-{
+static jfloat android_media_MediaSync_setPlaybackSettings(
+        JNIEnv *env, jobject thiz, jobject settings) {
     sp<JMediaSync> sync = getMediaSync(env, thiz);
     if (sync == NULL) {
         throwExceptionAsNecessary(env, INVALID_OPERATION);
-        return;
+        return (jfloat)0.f;
+    }
+
+    PlaybackSettings pbs;
+    pbs.fillFromJobject(env, gPlaybackSettingsFields, settings);
+    ALOGV("setPlaybackSettings: %d:%f %d:%f %d:%u %d:%u",
+            pbs.speedSet, pbs.audioRate.mSpeed,
+            pbs.pitchSet, pbs.audioRate.mPitch,
+            pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
+            pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
+
+    AudioPlaybackRate rate;
+    sync->getPlaybackSettings(&rate);
+    bool updatedRate = false;
+    if (pbs.speedSet) {
+        rate.mSpeed = pbs.audioRate.mSpeed;
+        updatedRate = true;
+    }
+    if (pbs.pitchSet) {
+        rate.mPitch = pbs.audioRate.mPitch;
+        updatedRate = true;
+    }
+    if (pbs.audioFallbackModeSet) {
+        rate.mFallbackMode = pbs.audioRate.mFallbackMode;
+        updatedRate = true;
+    }
+    if (pbs.audioStretchModeSet) {
+        rate.mStretchMode = pbs.audioRate.mStretchMode;
+        updatedRate = true;
+    }
+    if (updatedRate) {
+        status_t err = sync->setPlaybackSettings(rate);
+        if (err != OK) {
+            throwExceptionAsNecessary(env, err);
+            return (jfloat)0.f;
+        }
+    }
+
+    sp<const MediaClock> mediaClock = sync->getMediaClock();
+    if (mediaClock == NULL) {
+        return (jfloat)0.f;
+    }
+
+    return (jfloat)mediaClock->getPlaybackRate();
+}
+
+static jobject android_media_MediaSync_getPlaybackSettings(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return NULL;
+    }
+
+    PlaybackSettings pbs;
+    AudioPlaybackRate &audioRate = pbs.audioRate;
+    sync->getPlaybackSettings(&audioRate);
+    ALOGV("getPlaybackSettings: %f %f %d %d",
+            audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
+
+    pbs.speedSet = true;
+    pbs.pitchSet = true;
+    pbs.audioFallbackModeSet = true;
+    pbs.audioStretchModeSet = true;
+
+    return pbs.asJobject(env, gPlaybackSettingsFields);
+}
+
+static jfloat android_media_MediaSync_setSyncSettings(
+        JNIEnv *env, jobject thiz, jobject settings) {
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return (jfloat)0.f;
     }
 
     SyncSettings scs;
     scs.fillFromJobject(env, gSyncSettingsFields, settings);
     ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f",
-            scs.syncSourceSet, scs.syncSource,
-            scs.audioAdjustModeSet, scs.audioAdjustMode,
-            scs.toleranceSet, scs.tolerance,
+            scs.syncSourceSet, scs.sync.mSource,
+            scs.audioAdjustModeSet, scs.sync.mAudioAdjustMode,
+            scs.toleranceSet, scs.sync.mTolerance,
             scs.frameRateSet, scs.frameRate);
 
-    // TODO: pass sync settings to mediasync when it supports it
+    AVSyncSettings avsync;
+    sync->getSyncSettings(&avsync);
+    bool updatedSync = false;
+    status_t err = OK;
+    if (scs.syncSourceSet) {
+        avsync.mSource = scs.sync.mSource;
+        updatedSync = true;
+    }
+    if (scs.audioAdjustModeSet) {
+        avsync.mAudioAdjustMode = scs.sync.mAudioAdjustMode;
+        updatedSync = true;
+    }
+    if (scs.toleranceSet) {
+        avsync.mTolerance = scs.sync.mTolerance;
+        updatedSync = true;
+    }
+    if (updatedSync) {
+        err = sync->setSyncSettings(avsync);
+    }
+
+    if (scs.frameRateSet && err == OK) {
+        err = sync->setVideoFrameRateHint(scs.frameRate);
+    }
+    if (err != OK) {
+        throwExceptionAsNecessary(env, err);
+        return (jfloat)0.f;
+    }
+
+    sp<const MediaClock> mediaClock = sync->getMediaClock();
+    if (mediaClock == NULL) {
+        return (jfloat)0.f;
+    }
+
+    return (jfloat)mediaClock->getPlaybackRate();
 }
 
-static jobject
-android_media_MediaSync_getSyncSettings(JNIEnv *env, jobject thiz)
-{
+static jobject android_media_MediaSync_getSyncSettings(JNIEnv *env, jobject thiz) {
     sp<JMediaSync> sync = getMediaSync(env, thiz);
     if (sync == NULL) {
         throwExceptionAsNecessary(env, INVALID_OPERATION);
@@ -317,21 +441,25 @@
     }
 
     SyncSettings scs;
-    scs.syncSource = 0; // SYNC_SOURCE_DEFAULT
-    scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT
-    scs.tolerance = 0.f;
-    scs.frameRate = 0.f;
+    sync->getSyncSettings(&scs.sync);
+    scs.frameRate = sync->getVideoFrameRate();
 
-    // TODO: get this from mediaplayer when it supports it
-    // process_media_player_call(
-    //        env, thiz, mp->getSyncSettings(&scs), NULL, NULL);
     ALOGV("getSyncSettings: %d %d %f %f",
-            scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate);
+            scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
+
+    // sanity check settings
+    if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
+            || scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
+            || scs.sync.mTolerance < 0.f
+            || scs.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return NULL;
+    }
 
     scs.syncSourceSet = true;
     scs.audioAdjustModeSet = true;
     scs.toleranceSet = true;
-    scs.frameRateSet = false;
+    scs.frameRateSet = scs.frameRate >= 0.f;
 
     return scs.asJobject(env, gSyncSettingsFields);
 }
@@ -359,6 +487,7 @@
     CHECK(gFields.mediaTimestampClockRateID != NULL);
 
     gSyncSettingsFields.init(env);
+    gPlaybackSettingsFields.init(env);
 }
 
 static void android_media_MediaSync_native_setup(JNIEnv *env, jobject thiz) {
@@ -367,21 +496,6 @@
     setMediaSync(env, thiz, sync);
 }
 
-static void android_media_MediaSync_native_setPlaybackRate(
-        JNIEnv *env, jobject thiz, jfloat rate) {
-    sp<JMediaSync> sync = getMediaSync(env, thiz);
-    if (sync == NULL) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
-        return;
-    }
-
-    status_t err = sync->setPlaybackRate(rate);
-    if (err != NO_ERROR) {
-        throwExceptionAsNecessary(env, err);
-        return;
-    }
-}
-
 static void android_media_MediaSync_native_finalize(JNIEnv *env, jobject thiz) {
     android_media_MediaSync_release(env, thiz);
 }
@@ -416,11 +530,17 @@
 
     { "native_release", "()V", (void *)android_media_MediaSync_release },
 
-    { "native_setPlaybackRate", "(F)V", (void *)android_media_MediaSync_native_setPlaybackRate },
+    { "native_setPlaybackSettings", "(Landroid/media/PlaybackSettings;)F",
+      (void *)android_media_MediaSync_setPlaybackSettings },
 
-    { "setSyncSettings", "(Landroid/media/SyncSettings;)V", (void *)android_media_MediaSync_setSyncSettings},
+    { "getPlaybackSettings", "()Landroid/media/PlaybackSettings;",
+      (void *)android_media_MediaSync_getPlaybackSettings },
 
-    { "getSyncSettings", "()Landroid/media/SyncSettings;", (void *)android_media_MediaSync_getSyncSettings},
+    { "native_setSyncSettings", "(Landroid/media/SyncSettings;)F",
+      (void *)android_media_MediaSync_setSyncSettings },
+
+    { "getSyncSettings", "()Landroid/media/SyncSettings;",
+      (void *)android_media_MediaSync_getSyncSettings },
 
     { "native_finalize", "()V", (void *)android_media_MediaSync_native_finalize },
 };
diff --git a/media/jni/android_media_MediaSync.h b/media/jni/android_media_MediaSync.h
index cf81a72..80f5d63 100644
--- a/media/jni/android_media_MediaSync.h
+++ b/media/jni/android_media_MediaSync.h
@@ -18,11 +18,13 @@
 #define _ANDROID_MEDIA_MEDIASYNC_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaSync.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
 namespace android {
 
+struct AudioPlaybackRate;
 class AudioTrack;
 struct IGraphicBufferProducer;
 struct MediaClock;
@@ -32,17 +34,21 @@
     JMediaSync();
 
     status_t configureSurface(const sp<IGraphicBufferProducer> &bufferProducer);
-    status_t configureAudioTrack(
-            const sp<AudioTrack> &audioTrack, int32_t nativeSampleRateInHz);
+    status_t configureAudioTrack(const sp<AudioTrack> &audioTrack);
 
     status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
 
     status_t updateQueuedAudioData(int sizeInBytes, int64_t presentationTimeUs);
 
-    status_t setPlaybackRate(float rate);
-
     status_t getPlayTimeForPendingAudioFrames(int64_t *outTimeUs);
 
+    status_t setPlaybackSettings(const AudioPlaybackRate& rate);
+    void getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
+    status_t setSyncSettings(const AVSyncSettings& syncSettings);
+    void getSyncSettings(AVSyncSettings* syncSettings /* nonnull */);
+    status_t setVideoFrameRateHint(float rate);
+    float getVideoFrameRate();
+
     sp<const MediaClock> getMediaClock();
 
 protected:
diff --git a/media/jni/android_media_SyncSettings.cpp b/media/jni/android_media_SyncSettings.cpp
index 2f0605e..5da35e7 100644
--- a/media/jni/android_media_SyncSettings.cpp
+++ b/media/jni/android_media_SyncSettings.cpp
@@ -57,9 +57,9 @@
 }
 
 void SyncSettings::fillFromJobject(JNIEnv *env, const fields_t& fields, jobject settings) {
-    syncSource = env->GetIntField(settings, fields.sync_source);
-    audioAdjustMode = env->GetIntField(settings, fields.audio_adjust_mode);
-    tolerance = env->GetFloatField(settings, fields.tolerance);
+    sync.mSource = (AVSyncSource)env->GetIntField(settings, fields.sync_source);
+    sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)env->GetIntField(settings, fields.audio_adjust_mode);
+    sync.mTolerance = env->GetFloatField(settings, fields.tolerance);
     frameRate = env->GetFloatField(settings, fields.frame_rate);
     int set = env->GetIntField(settings, fields.set);
 
@@ -74,9 +74,9 @@
     if (settings == NULL) {
         return NULL;
     }
-    env->SetIntField(settings, fields.sync_source, (jint)syncSource);
-    env->SetIntField(settings, fields.audio_adjust_mode, (jint)audioAdjustMode);
-    env->SetFloatField(settings, fields.tolerance, (jfloat)tolerance);
+    env->SetIntField(settings, fields.sync_source, (jint)sync.mSource);
+    env->SetIntField(settings, fields.audio_adjust_mode, (jint)sync.mAudioAdjustMode);
+    env->SetFloatField(settings, fields.tolerance, (jfloat)sync.mTolerance);
     env->SetFloatField(settings, fields.frame_rate, (jfloat)frameRate);
     env->SetIntField(
             settings, fields.set,
diff --git a/media/jni/android_media_SyncSettings.h b/media/jni/android_media_SyncSettings.h
index 586533f..23530db 100644
--- a/media/jni/android_media_SyncSettings.h
+++ b/media/jni/android_media_SyncSettings.h
@@ -19,13 +19,12 @@
 
 #include "jni.h"
 
+#include <media/stagefright/MediaSync.h>
+
 namespace android {
 
 struct SyncSettings {
-    // keep this here until it is implemented
-    int syncSource;
-    int audioAdjustMode;
-    float tolerance;
+    AVSyncSettings sync;
     float frameRate;
 
     bool syncSourceSet;
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index c364d469..96b72a2 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -25,6 +25,8 @@
 #include <android_runtime/AndroidRuntime.h>
 #include "media/AudioEffect.h"
 
+#include <ScopedUtfChars.h>
+
 using namespace android;
 
 #define AUDIOEFFECT_SUCCESS                      0
@@ -249,7 +251,8 @@
 
 static jint
 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
+        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId,
+        jobjectArray javadesc, jstring opPackageName)
 {
     ALOGV("android_media_AudioEffect_native_setup");
     AudioEffectJniStorage* lpJniStorage = NULL;
@@ -267,6 +270,8 @@
     jstring jdescName;
     jstring jdescImplementor;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     if (type != NULL) {
         typeStr = env->GetStringUTFChars(type, NULL);
         if (typeStr == NULL) {  // Out of memory
@@ -312,6 +317,7 @@
 
     // create the native AudioEffect object
     lpAudioEffect = new AudioEffect(typeStr,
+                                    String16(opPackageNameStr.c_str()),
                                     uuidStr,
                                     priority,
                                     effectCallback,
@@ -868,7 +874,7 @@
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
                                          (void *)android_media_AudioEffect_native_setup},
     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 460277f..abc681e 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -26,6 +26,8 @@
 #include <utils/threads.h>
 #include "media/Visualizer.h"
 
+#include <ScopedUtfChars.h>
+
 using namespace android;
 
 #define VISUALIZER_SUCCESS                      0
@@ -331,7 +333,7 @@
 
 static jint
 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jint sessionId, jintArray jId)
+        jint sessionId, jintArray jId, jstring opPackageName)
 {
     ALOGV("android_media_visualizer_native_setup");
     visualizerJniStorage* lpJniStorage = NULL;
@@ -339,6 +341,8 @@
     Visualizer* lpVisualizer = NULL;
     jint* nId = NULL;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     lpJniStorage = new visualizerJniStorage();
     if (lpJniStorage == NULL) {
         ALOGE("setup: Error creating JNI Storage");
@@ -362,7 +366,8 @@
     }
 
     // create the native Visualizer object
-    lpVisualizer = new Visualizer(0,
+    lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
+                                  0,
                                   android_media_visualizer_effect_callback,
                                   lpJniStorage,
                                   sessionId);
@@ -662,7 +667,7 @@
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
-    {"native_setup",           "(Ljava/lang/Object;I[I)I",
+    {"native_setup",           "(Ljava/lang/Object;I[ILjava/lang/String;)I",
                                           (void *)android_media_visualizer_native_setup},
     {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
     {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 25c6154..84ae3b4 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -514,10 +514,11 @@
         if (strncmp(mime, "audio/", 6) == 0) {
 
             AMediaCodec *codec = AMediaCodec_createDecoderByType(mime);
-            if (AMediaCodec_configure(codec, format,
-                    NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
-                || AMediaCodec_start(codec) != AMEDIA_OK
-                || AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
+            if (codec == NULL
+                    || AMediaCodec_configure(codec, format,
+                            NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
+                    || AMediaCodec_start(codec) != AMEDIA_OK
+                    || AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
                 AMediaExtractor_delete(ex);
                 AMediaCodec_delete(codec);
                 AMediaFormat_delete(format);
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ddb01a0..0521833 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -27,18 +27,16 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
-        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
-    }
+    SkBitmap bm;
+    GraphicsJNI::getSkBitmap(env, jbitmap, &bm);
 
     if (info) {
-        info->width     = bm->width();
-        info->height    = bm->height();
-        info->stride    = bm->rowBytes();
+        info->width     = bm.width();
+        info->height    = bm.height();
+        info->stride    = bm.rowBytes();
         info->flags     = 0;
 
-        switch (bm->colorType()) {
+        switch (bm.colorType()) {
             case kN32_SkColorType:
                 info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
                 break;
@@ -64,17 +62,18 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
+    SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
+    if (!pixelRef) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
 
-    bm->lockPixels();
-    void* addr = bm->getPixels();
+    pixelRef->lockPixels();
+    void* addr = pixelRef->pixels();
     if (NULL == addr) {
-        bm->unlockPixels();
+        pixelRef->unlockPixels();
         return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
     }
+    pixelRef->ref();
 
     if (addrPtr) {
         *addrPtr = addr;
@@ -87,8 +86,8 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
-    if (NULL == bm) {
+    SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
+    if (!pixelRef) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
 
@@ -96,9 +95,11 @@
     // bitmaps.  Note that this will slow down read-only accesses to the
     // bitmaps, but the NDK methods are primarily intended to be used for
     // writes.
-    bm->notifyPixelsChanged();
+    pixelRef->notifyPixelsChanged();
 
-    bm->unlockPixels();
+    pixelRef->unlockPixels();
+    pixelRef->unref();
+
     return ANDROID_BITMAP_RESULT_SUCCESS;
 }
 
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index dc7c945..d2a6424 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -71,5 +71,5 @@
     </plurals>
     <string name="notification_touch_for_details" msgid="4483108577842961665">"Толығырақ мәліметті көру үшін түртіңіз"</string>
     <string name="retry" msgid="7564024179122207376">"Қайталау"</string>
-    <string name="copy_failure_alert_content" msgid="3715575000297709082">"Бұл файлдар көшірілмейді: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+    <string name="copy_failure_alert_content" msgid="3715575000297709082">"Мына файлдар көшірілген жоқ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index f7c6c45..1b15b9f9 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -66,8 +66,8 @@
     </plurals>
     <string name="copy_preparing" msgid="3896202461003039386">"Nuxsa olishga tayyorgarlik..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
-      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
-      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
     </plurals>
     <string name="notification_touch_for_details" msgid="4483108577842961665">"Batafsil ma’lumot olish uchun bosing"</string>
     <string name="retry" msgid="7564024179122207376">"Qayta urinish"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 744ace1..96e3e3d 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -65,9 +65,11 @@
       <item quantity="one">正在复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
     </plurals>
     <string name="copy_preparing" msgid="3896202461003039386">"正在准备复制…"</string>
-    <!-- no translation found for copy_error_notification_title (5267616889076217261) -->
+    <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
+      <item quantity="other">无法复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+      <item quantity="one">无法复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+    </plurals>
     <string name="notification_touch_for_details" msgid="4483108577842961665">"触摸可查看详情"</string>
     <string name="retry" msgid="7564024179122207376">"重试"</string>
-    <!-- no translation found for copy_failure_alert_content (3715575000297709082) -->
-    <skip />
+    <string name="copy_failure_alert_content" msgid="3715575000297709082">"以下文件无法复制:<xliff:g id="LIST">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 352ba9e..1fa402e 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -71,5 +71,5 @@
     </plurals>
     <string name="notification_touch_for_details" msgid="4483108577842961665">"輕觸即可查看詳情"</string>
     <string name="retry" msgid="7564024179122207376">"重試"</string>
-    <string name="copy_failure_alert_content" msgid="3715575000297709082">"以下檔案不會被複製:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+    <string name="copy_failure_alert_content" msgid="3715575000297709082">"以下檔案未能複製:<xliff:g id="LIST">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 1699809..25b1875 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -120,7 +120,7 @@
             KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(
                     true /* bypassHandler */);
             getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
-                    new UserHandle(mLockPatternUtils.getCurrentUser()));
+                    new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
         }
     }
 
@@ -138,7 +138,7 @@
                     visible = mEnableEmergencyCallWhileSimLocked;
                 } else {
                     // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
-                    visible = mLockPatternUtils.isSecure();
+                    visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
                 }
             }
         }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 322be91..c4f4b9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -63,7 +63,8 @@
         // start fresh
         resetPasswordText(false /* animate */);
         // if the user is currently locked out, enforce it.
-        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+        long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+                KeyguardUpdateMonitor.getCurrentUser());
         if (shouldLockout(deadline)) {
             handleAttemptLockout(deadline);
         } else {
@@ -106,7 +107,7 @@
 
     protected void verifyPasswordAndUnlock() {
         String entry = getPasswordText();
-        if (mLockPatternUtils.checkPassword(entry)) {
+        if (mLockPatternUtils.checkPassword(entry, KeyguardUpdateMonitor.getCurrentUser())) {
             mCallback.reportUnlockAttempt(true);
             mCallback.dismiss(true);
         } else {
@@ -116,7 +117,8 @@
                 mCallback.reportUnlockAttempt(false);
                 int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
                 if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
-                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+                            KeyguardUpdateMonitor.getCurrentUser());
                     handleAttemptLockout(deadline);
                 }
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index be71b034..2cf30ba 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -71,7 +71,7 @@
 
         @Override
         public void onTrustGrantedWithFlags(int flags, int userId) {
-            if (userId != mLockPatternUtils.getCurrentUser()) return;
+            if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
             if (!isAttachedToWindow()) return;
             boolean bouncerVisible = isVisibleToUser();
             boolean initiatedByUser =
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 9aa5729..557cd13 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -130,7 +130,8 @@
         mLockPatternView.setOnPatternListener(new UnlockPatternListener());
 
         // stealth mode will be the same for the life of this screen
-        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
+        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+                KeyguardUpdateMonitor.getCurrentUser()));
 
         // vibrate mode will be the same for the life of this screen
         mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
@@ -176,7 +177,8 @@
         mLockPatternView.clearPattern();
 
         // if the user is currently locked out, enforce it.
-        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+        long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+                KeyguardUpdateMonitor.getCurrentUser());
         if (deadline != 0) {
             handleAttemptLockout(deadline);
         } else {
@@ -213,7 +215,7 @@
         }
 
         public void onPatternDetected(List<LockPatternView.Cell> pattern) {
-            if (mLockPatternUtils.checkPattern(pattern)) {
+            if (mLockPatternUtils.checkPattern(pattern, KeyguardUpdateMonitor.getCurrentUser())) {
                 mCallback.reportUnlockAttempt(true);
                 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
                 mCallback.dismiss(true);
@@ -230,7 +232,8 @@
                 int attempts = mKeyguardUpdateMonitor.getFailedUnlockAttempts();
                 if (registeredAttempt &&
                         0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
-                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+                            KeyguardUpdateMonitor.getCurrentUser());
                     handleAttemptLockout(deadline);
                 } else {
                     mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5af7783..ae4baad 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -261,7 +261,7 @@
 
         SecurityMode mode = mSecurityModel.getSecurityMode();
         final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
-        final int currentUser = mLockPatternUtils.getCurrentUser();
+        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
         final int failedAttemptsBeforeWipe =
                 dpm.getMaximumFailedPasswordsForWipe(null, currentUser);
@@ -296,7 +296,7 @@
                 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
         }
         monitor.reportFailedUnlockAttempt();
-        mLockPatternUtils.reportFailedPasswordAttempt();
+        mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
         if (showTimeout) {
             showTimeoutDialog();
         }
@@ -321,7 +321,7 @@
     boolean showNextSecurityScreenOrFinish(boolean authenticated) {
         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
         boolean finish = false;
-        if (mUpdateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+        if (mUpdateMonitor.getUserHasTrust(KeyguardUpdateMonitor.getCurrentUser())) {
             finish = true;
         } else if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode();
@@ -430,7 +430,8 @@
             KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
             if (success) {
                 monitor.clearFailedUnlockAttempts();
-                mLockPatternUtils.reportSuccessfulPasswordAttempt();
+                mLockPatternUtils.reportSuccessfulPasswordAttempt(
+                        KeyguardUpdateMonitor.getCurrentUser());
             } else {
                 KeyguardSecurityContainer.this.reportFailedUnlockAttempt();
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 3eb31ad..454221a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -67,7 +67,8 @@
             return SecurityMode.SimPuk;
         }
 
-        final int security = mLockPatternUtils.getActivePasswordQuality();
+        final int security = mLockPatternUtils.getActivePasswordQuality(
+                KeyguardUpdateMonitor.getCurrentUser());
         switch (security) {
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index af6360a..4e9621a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -200,9 +200,10 @@
     private String getOwnerInfo() {
         ContentResolver res = getContext().getContentResolver();
         String info = null;
-        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+                KeyguardUpdateMonitor.getCurrentUser());
         if (ownerInfoEnabled) {
-            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+            info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
         }
         return info;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1eec5325..b8d9053 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -244,6 +244,16 @@
     private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
     private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
 
+    private static int sCurrentUser;
+
+    public synchronized static void setCurrentUser(int currentUser) {
+        sCurrentUser = currentUser;
+    }
+
+    public synchronized static int getCurrentUser() {
+        return sCurrentUser;
+    }
+
     @Override
     public void onTrustChanged(boolean enabled, int userId, int flags) {
         mUserHasTrust.put(userId, enabled);
@@ -669,7 +679,7 @@
                 cb.onScreenTurnedOn();
             }
         }
-        startListeningForFingerprint();
+        updateFingerprintListeningState();
     }
 
     protected void handleScreenTurnedOff(int arg1) {
@@ -681,7 +691,7 @@
                 cb.onScreenTurnedOff(arg1);
             }
         }
-        stopListeningForFingerprint();
+        updateFingerprintListeningState();
     }
 
     /**
@@ -754,14 +764,14 @@
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
                                     newUserId, 0, reply));
                             mSwitchingUser = true;
-                            stopListeningForFingerprint();
+                            updateFingerprintListeningState();
                         }
                         @Override
                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
                                     newUserId, 0));
                             mSwitchingUser = false;
-                            startListeningForFingerprint();
+                            updateFingerprintListeningState();
                         }
                         @Override
                         public void onForegroundProfileSwitch(int newProfileId) {
@@ -777,7 +787,20 @@
         trustManager.registerTrustListener(this);
 
         mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
-        startListeningForFingerprint();
+        updateFingerprintListeningState();
+    }
+
+    private void updateFingerprintListeningState() {
+        boolean shouldListenForFingerprint = shouldListenForFingerprint();
+        if (mFingerprintDetectionRunning && !shouldListenForFingerprint) {
+            stopListeningForFingerprint();
+        } else if (!mFingerprintDetectionRunning && shouldListenForFingerprint) {
+            startListeningForFingerprint();
+        }
+    }
+
+    private boolean shouldListenForFingerprint() {
+        return mScreenOn && mKeyguardIsVisible && !mSwitchingUser;
     }
 
     private void startListeningForFingerprint() {
@@ -794,7 +817,7 @@
         }
     }
 
-    public void stopListeningForFingerprint() {
+    private void stopListeningForFingerprint() {
         if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
         if (isFingerprintDetectionRunning()) {
             mFingerprintCancelSignal.cancel();
@@ -1052,6 +1075,7 @@
                 cb.onKeyguardVisibilityChangedRaw(isShowing);
             }
         }
+        updateFingerprintListeningState();
     }
 
     /**
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b5e49ce..6876222 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -67,6 +67,10 @@
 
     <!-- Status message of Wi-Fi when it is connected by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
     <string name="connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
+    <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
+    <string name="connected_via_passpoint">Connected via %1$s</string>
+    <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
+    <string name="available_via_passpoint">Available via %1$s</string>
 
     <!-- Bluetooth settings.  Message when a device is disconnected -->
     <string name="bluetooth_disconnected">Disconnected</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e8ab220..2fde4f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -26,6 +26,7 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.LruCache;
 
@@ -199,7 +200,10 @@
     }
 
     public boolean matches(WifiConfiguration config) {
-        return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
+        if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint())
+            return config.FQDN.equals(mConfig.providerFriendlyName);
+        else
+            return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
     }
 
     public WifiConfiguration getConfig() {
@@ -265,19 +269,47 @@
         return ssid;
     }
 
+    public String getConfigName() {
+        if (mConfig != null && mConfig.isPasspoint()) {
+            return mConfig.providerFriendlyName;
+        } else {
+            return ssid;
+        }
+    }
+
     public DetailedState getDetailedState() {
         return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
     }
 
+    public String getSavedNetworkSummary() {
+        // Update to new summary
+        if (mConfig != null && mConfig.isPasspoint()) {
+            return "";
+        } else {
+            return getSettingsSummary();
+        }
+    }
+
     public String getSummary() {
+        return getSettingsSummary();
+    }
+
+    public String getSettingsSummary() {
         // Update to new summary
         StringBuilder summary = new StringBuilder();
 
-        if (isActive()) { // This is the active connection
+        if (isActive() && mConfig != null && mConfig.isPasspoint()) {
+            // This is the active connection on passpoint
+            summary.append(getSummary(mContext, getDetailedState(),
+                    false, mConfig.providerFriendlyName));
+        } else if (isActive()) {
+            // This is the active connection on non-passpoint network
             summary.append(getSummary(mContext, getDetailedState(),
                     networkId == WifiConfiguration.INVALID_NETWORK_ID));
-        } else if (mConfig != null
-                && mConfig.hasNoInternetAccess()) {
+        } else if (mConfig != null && mConfig.isPasspoint()) {
+            String format = mContext.getString(R.string.available_via_passpoint);
+            summary.append(String.format(format, mConfig.providerFriendlyName));
+        } else if (mConfig != null && mConfig.hasNoInternetAccess()) {
             summary.append(mContext.getString(R.string.wifi_no_internet));
         } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
                 mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
@@ -559,7 +591,11 @@
     }
 
     void loadConfig(WifiConfiguration config) {
-        ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+        if (config.isPasspoint())
+            ssid = config.providerFriendlyName;
+        else
+            ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+            
         security = getSecurity(config);
         networkId = config.networkId;
         mConfig = config;
@@ -643,11 +679,25 @@
         return reorder;
     }
 
+    void update(WifiConfiguration config) {
+        mConfig = config;
+        networkId = config.networkId;
+        if (mAccessPointListener != null) {
+            mAccessPointListener.onAccessPointChanged(this);
+        }
+    }
+    
     public static String getSummary(Context context, String ssid, DetailedState state,
-            boolean isEphemeral) {
-        if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) {
-            // Special case for connected + ephemeral networks.
-            return context.getString(R.string.connected_via_wfa);
+            boolean isEphemeral, String passpointProvider) {
+        if (state == DetailedState.CONNECTED && ssid == null) {
+            if (TextUtils.isEmpty(passpointProvider) == false) {
+                // Special case for connected + passpoint networks.
+                String format = context.getString(R.string.connected_via_passpoint);
+                return String.format(format, passpointProvider);
+            } else if (isEphemeral) {
+                // Special case for connected + ephemeral networks.
+                return context.getString(R.string.connected_via_wfa);
+            }
         }
 
         String[] formats = context.getResources().getStringArray((ssid == null)
@@ -661,7 +711,12 @@
     }
 
     public static String getSummary(Context context, DetailedState state, boolean isEphemeral) {
-        return getSummary(context, null, state, isEphemeral);
+        return getSummary(context, null, state, isEphemeral, null);
+    }
+
+    public static String getSummary(Context context, DetailedState state, boolean isEphemeral,
+            String passpointProvider) {
+        return getSummary(context, null, state, isEphemeral, passpointProvider);
     }
 
     public static String convertToQuotedString(String string) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 2eb7abf..09e6912 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -61,6 +61,7 @@
     private final WifiListener mListener;
     private final boolean mIncludeSaved;
     private final boolean mIncludeScans;
+    private final boolean mIncludePasspoints;
 
     private boolean mSavedNetworksExist;
     private boolean mRegistered;
@@ -74,14 +75,18 @@
     Scanner mScanner;
 
     public WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
-            boolean includeScans) {
-        this(context, wifiListener, includeSaved, includeScans,
+                       boolean includeScans) {
+        this(context, wifiListener, includeSaved, includeScans, false);
+    }
+    public WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
+            boolean includeScans, boolean includePasspoints) {
+        this(context, wifiListener, includeSaved, includeScans, includePasspoints,
                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE));
     }
 
     @VisibleForTesting
     WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
-            boolean includeScans, WifiManager wifiManager) {
+            boolean includeScans, boolean includePasspoints, WifiManager wifiManager) {
         if (!includeSaved && !includeScans) {
             throw new IllegalArgumentException("Must include either saved or scans");
         }
@@ -89,6 +94,7 @@
         mWifiManager = wifiManager;
         mIncludeSaved = includeSaved;
         mIncludeScans = includeScans;
+        mIncludePasspoints = includePasspoints;
         mListener = wifiListener;
 
         // check if verbose logging has been turned on or off
@@ -220,21 +226,31 @@
         /** Lookup table to more quickly update AccessPoints by only considering objects with the
          * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
         Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
+        WifiConfiguration connectionConfig = null;
 
         final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
         if (configs != null) {
             mSavedNetworksExist = configs.size() != 0;
             for (WifiConfiguration config : configs) {
+                if (mLastInfo != null && mLastInfo.getNetworkId() == config.networkId) {
+                    connectionConfig = config;
+                }
                 if (config.selfAdded && config.numAssociation == 0) {
                     continue;
                 }
                 AccessPoint accessPoint = getCachedOrCreate(config);
                 if (mLastInfo != null && mLastNetworkInfo != null) {
-                    accessPoint.update(mLastInfo, mLastNetworkInfo);
+                    if (config.isPasspoint() == false) {
+                        accessPoint.update(mLastInfo, mLastNetworkInfo);
+                    }
                 }
                 if (mIncludeSaved) {
-                    mAccessPoints.add(accessPoint);
-                    apMap.put(accessPoint.getSsid(), accessPoint);
+                    if (!config.isPasspoint() || mIncludePasspoints)
+                        mAccessPoints.add(accessPoint);
+
+                    if (config.isPasspoint() == false) {
+                        apMap.put(accessPoint.getSsid(), accessPoint);
+                    }
                 } else {
                     // If we aren't using saved networks, drop them into the cache so that
                     // we have access to their saved info.
@@ -264,6 +280,22 @@
                     if (mLastInfo != null && mLastNetworkInfo != null) {
                         accessPoint.update(mLastInfo, mLastNetworkInfo);
                     }
+
+                    if (result.passpointNetwork) {
+                        WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
+                        if (config != null) {
+                            accessPoint.update(config);
+                        }
+                    }
+
+                    if (mLastInfo != null && mLastInfo.getBSSID() != null
+                            && mLastInfo.getBSSID().equals(result.BSSID)
+                            && connectionConfig != null && connectionConfig.isPasspoint()) {
+                        /* This network is connected via this passpoint config */
+                        /* SSID match is not going to work for it; so update explicitly */
+                        accessPoint.update(connectionConfig);
+                    }
+
                     mAccessPoints.add(accessPoint);
                     apMap.put(accessPoint.getSsid(), accessPoint);
                 }
@@ -354,8 +386,9 @@
     }
 
     public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
-            boolean includeScans) {
-        WifiTracker tracker = new WifiTracker(context, null, includeSaved, includeScans);
+            boolean includeScans, boolean includePasspoints) {
+        WifiTracker tracker = new WifiTracker(context,
+                null, includeSaved, includeScans, includePasspoints);
         tracker.forceUpdate();
         return tracker.getAccessPoints();
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 870f043..7bf2223 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, null);
+                    lpu.saveLockPattern(cellPattern, null, UserHandle.USER_OWNER);
                 } catch (IllegalArgumentException e) {
                     // Don't want corrupted lock pattern to hang the reboot process
                 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 7f826ef..d99f741 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -754,7 +754,7 @@
      */
     private byte[] getLockSettings() {
         final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
-        final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled();
+        final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(UserHandle.myUserId());
         final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -871,7 +871,8 @@
                 }
                 switch (key) {
                     case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
-                        lockPatternUtils.setOwnerInfoEnabled("1".equals(value));
+                        lockPatternUtils.setOwnerInfoEnabled("1".equals(value),
+                                UserHandle.myUserId());
                         break;
                     case KEY_LOCK_SETTINGS_OWNER_INFO:
                         lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml
new file mode 100644
index 0000000..c6a4622
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="rotation"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="566"
+            android:propertyName="rotation"
+            android:valueFrom="0.0"
+            android:valueTo="-305.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="1066"
+            android:propertyName="rotation"
+            android:valueFrom="-305.0"
+            android:valueTo="-305.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+        <objectAnimator
+            android:duration="800"
+            android:propertyName="rotation"
+            android:valueFrom="-305.0"
+            android:valueTo="-720.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml
new file mode 100644
index 0000000..0e2c2f0
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="rotation"
+            android:valueFrom="285.0"
+            android:valueTo="285.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="516"
+            android:propertyName="rotation"
+            android:valueFrom="285.0"
+            android:valueTo="90.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml
new file mode 100644
index 0000000..c01010d
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="283"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="283"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="283"
+            android:propertyName="rotation"
+            android:valueFrom="184.0"
+            android:valueTo="184.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="rotation"
+            android:valueFrom="184.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml
new file mode 100644
index 0000000..454be24
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="233"
+            android:propertyName="trimPathStart"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="466"
+            android:propertyName="trimPathStart"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml
new file mode 100644
index 0000000..faeecf4
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="133"
+        android:propertyName="trimPathEnd"
+        android:valueFrom="0.0"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml
new file mode 100644
index 0000000..3bacf03
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="66"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml
new file mode 100644
index 0000000..80a0faa
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="116"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="116"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+    </set>
+    <objectAnimator
+        android:duration="166"
+        android:propertyName="trimPathStart"
+        android:valueFrom="1.0"
+        android:valueTo="0.0"
+        android:valueType="floatType"
+        android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml
new file mode 100644
index 0000000..3a18296
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml
new file mode 100644
index 0000000..1e16df7
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="166"
+        android:propertyName="trimPathEnd"
+        android:valueFrom="0.0"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="150"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml
new file mode 100644
index 0000000..a1cf8df
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="150"
+        android:propertyName="trimPathStart"
+        android:valueFrom="0.0"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/linear" />
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml
new file mode 100644
index 0000000..f88c070
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyName="trimPathEnd"
+        android:valueFrom="0.0"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="216"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml
new file mode 100644
index 0000000..ada7c10
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="216"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml
new file mode 100644
index 0000000..e6b12da
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="216"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="266"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml
new file mode 100644
index 0000000..8c6e71d
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="150"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml
new file mode 100644
index 0000000..c6a4622
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="rotation"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="566"
+            android:propertyName="rotation"
+            android:valueFrom="0.0"
+            android:valueTo="-305.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+        <objectAnimator
+            android:duration="1066"
+            android:propertyName="rotation"
+            android:valueFrom="-305.0"
+            android:valueTo="-305.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+        <objectAnimator
+            android:duration="800"
+            android:propertyName="rotation"
+            android:valueFrom="-305.0"
+            android:valueTo="-720.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml
new file mode 100644
index 0000000..cc8aba9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="lockscreen_fingerprint_error_state"
+    android:width="32dp"
+    android:viewportWidth="32"
+    android:height="32dp"
+    android:viewportHeight="32" >
+    <group
+        android:name="white_fingerprint_ridges"
+        android:translateX="16.125"
+        android:translateY="19.75" >
+        <group
+            android:name="white_fingerprint_ridges_pivot"
+            android:translateX="33.2085"
+            android:translateY="30.91685" >
+            <group
+                android:name="ridge_5" >
+                <path
+                    android:name="ridge_5_path"
+                    android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0.5"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round" />
+            </group>
+            <group
+                android:name="ridge_4" >
+                <path
+                    android:name="ridge_7_path"
+                    android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0.5"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round" />
+            </group>
+            <group
+                android:name="ridge_3" >
+                <path
+                    android:name="ridge_6_path"
+                    android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0.5"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round" />
+            </group>
+            <group
+                android:name="ridge_2" >
+                <path
+                    android:name="ridge_2_path"
+                    android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0.5"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round" />
+            </group>
+            <group
+                android:name="ridge_1"
+                android:translateX="-97.5"
+                android:translateY="-142.5" >
+                <path
+                    android:name="ridge_1_path"
+                    android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0.5"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round" />
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="fingerprint_ridges"
+        android:translateX="16.125"
+        android:translateY="19.75" >
+        <group
+            android:name="fingerprint_ridges_pivot"
+            android:translateX="33.2085"
+            android:translateY="30.91685" >
+            <group
+                android:name="ridge_6" >
+                <path
+                    android:name="ridge_5_path_0"
+                    android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
+                    android:strokeColor="#FFF2501D"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round"
+                    android:trimPathEnd="0" />
+            </group>
+            <group
+                android:name="ridge_7" >
+                <path
+                    android:name="ridge_7_path_0"
+                    android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
+                    android:strokeColor="#FFF2501D"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round"
+                    android:trimPathEnd="0" />
+            </group>
+            <group
+                android:name="ridge_8" >
+                <path
+                    android:name="ridge_6_path_0"
+                    android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
+                    android:strokeColor="#FFF2501D"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round"
+                    android:trimPathEnd="0" />
+            </group>
+            <group
+                android:name="ridge_9" >
+                <path
+                    android:name="ridge_2_path_0"
+                    android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
+                    android:strokeColor="#FFF2501D"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round"
+                    android:trimPathStart="1" />
+            </group>
+            <group
+                android:name="ridge_10"
+                android:translateX="-97.5"
+                android:translateY="-142.5" >
+                <path
+                    android:name="ridge_1_path_0"
+                    android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
+                    android:strokeColor="#FFF2501D"
+                    android:strokeWidth="1.45"
+                    android:strokeLineCap="round"
+                    android:trimPathEnd="0" />
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="exclamation"
+        android:translateX="16"
+        android:translateY="16" >
+        <group
+            android:name="group_2"
+            android:scaleX="0"
+            android:scaleY="0"
+            android:rotation="184" >
+            <path
+                android:name="path_2_merged"
+                android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
+                android:fillColor="#FFF2501D" />
+        </group>
+    </group>
+    <group
+        android:name="circle_outline"
+        android:translateX="16"
+        android:translateY="16" >
+        <group
+            android:name="group_1"
+            android:scaleX="1.12734"
+            android:scaleY="1.12734"
+            android:rotation="285" >
+            <path
+                android:name="path_3"
+                android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
+                android:strokeColor="#FFF2501D"
+                android:strokeWidth="2"
+                android:trimPathStart="1" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml
new file mode 100644
index 0000000..8cc8ac2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/lockscreen_fingerprint_error_state" >
+    <target
+        android:name="white_fingerprint_ridges"
+        android:animation="@anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation" />
+    <target
+        android:name="ridge_5_path"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_5_path_animation" />
+    <target
+        android:name="ridge_7_path"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_7_path_animation" />
+    <target
+        android:name="ridge_6_path"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_6_path_animation" />
+    <target
+        android:name="ridge_2_path"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_2_path_animation" />
+    <target
+        android:name="ridge_1_path"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_1_path_animation" />
+    <target
+        android:name="fingerprint_ridges"
+        android:animation="@anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation" />
+    <target
+        android:name="ridge_5_path_0"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation" />
+    <target
+        android:name="ridge_7_path_0"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation" />
+    <target
+        android:name="ridge_6_path_0"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation" />
+    <target
+        android:name="ridge_2_path_0"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation" />
+    <target
+        android:name="ridge_1_path_0"
+        android:animation="@anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation" />
+    <target
+        android:name="group_2"
+        android:animation="@anim/lockscreen_fingerprint_error_state_group_2_animation" />
+    <target
+        android:name="group_1"
+        android:animation="@anim/lockscreen_fingerprint_error_state_group_1_animation" />
+    <target
+        android:name="path_3"
+        android:animation="@anim/lockscreen_fingerprint_error_state_path_3_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml
new file mode 100644
index 0000000..39c5211
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml
new file mode 100644
index 0000000..d3ae9d7
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.0,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml
new file mode 100644
index 0000000..e10db01
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.8,0.0 0.5,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml
new file mode 100644
index 0000000..736eac6
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index fca8231..1057464 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -61,7 +61,7 @@
         android:scaleType="center"
         android:contentDescription="@string/accessibility_phone_button" />
 
-    <com.android.systemui.statusbar.KeyguardAffordanceView
+    <com.android.systemui.statusbar.phone.LockIcon
         android:id="@+id/lock_icon"
         android:layout_width="@dimen/keyguard_affordance_width"
         android:layout_height="@dimen/keyguard_affordance_height"
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 2eb99ba..ddff0f0 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -18,7 +18,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:background="@drawable/qs_detail_background"
-        android:paddingBottom="16dp"
+        android:paddingBottom="8dp"
         android:orientation="vertical">
 
     <FrameLayout
@@ -30,7 +30,7 @@
     <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingEnd="16dp"
+            android:paddingEnd="8dp"
             android:gravity="end">
 
         <TextView
diff --git a/packages/SystemUI/res/layout/segmented_button.xml b/packages/SystemUI/res/layout/segmented_button.xml
index ead735f..b7a7932 100644
--- a/packages/SystemUI/res/layout/segmented_button.xml
+++ b/packages/SystemUI/res/layout/segmented_button.xml
@@ -19,10 +19,10 @@
     android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/segmented_button_spacing"
     android:layout_weight="1"
-    android:paddingStart="8dp"
-    android:gravity="start|center_vertical"
+    android:gravity="center"
     android:maxLines="2"
+    android:lineSpacingMultiplier="1.05026"
     android:textColor="@color/segmented_button_text_selector"
     android:background="@drawable/btn_borderless_rect"
-    android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary"
-    android:minHeight="48dp" />
+    android:textAppearance="@style/TextAppearance.QS.SegmentedButton"
+    android:minHeight="64dp" />
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index c86e9dc..0ed1e2a 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -21,40 +21,31 @@
     android:layout_marginBottom="4dp"
     android:layout_marginLeft="@dimen/notification_side_padding"
     android:layout_marginRight="@dimen/notification_side_padding"
-    android:layout_marginTop="4dp"
     android:background="@drawable/volume_dialog_background"
     android:translationZ="4dp" >
 
     <com.android.keyguard.AlphaOptimizedImageButton
         android:id="@+id/volume_expand_button"
         style="@style/VolumeButtons"
-        android:layout_alignParentLeft="true"
         android:layout_width="@dimen/volume_button_size"
         android:layout_height="@dimen/volume_button_size"
+        android:layout_alignParentLeft="true"
         android:clickable="true"
         android:soundEffectsEnabled="false"
-        android:src="@drawable/ic_volume_collapse_animation" />
+        android:src="@drawable/ic_volume_collapse_animation"
+        tools:ignore="RtlHardcoded" />
 
     <LinearLayout
         android:id="@+id/volume_dialog_content"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
-        android:paddingBottom="4dp"
-        android:paddingTop="6dp" >
+        android:paddingBottom="8dp"
+        android:paddingTop="8dp" >
 
         <!-- volume rows added and removed here! :-) -->
 
-        <FrameLayout
-            android:id="@+id/volume_footer"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            tools:ignore="UselessParent" >
-
-            <include layout="@layout/volume_text_footer" />
-
-            <include layout="@layout/volume_zen_footer" />
-        </FrameLayout>
+        <include layout="@layout/volume_zen_footer" />
     </LinearLayout>
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index b51aa96..53ae61b 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -16,16 +16,15 @@
 <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" >
+    android:clipChildren="false"
+    android:paddingEnd="8dp"
+    android:paddingStart="8dp" >
 
     <TextView
         android:id="@+id/volume_row_header"
         style="?android:attr/textAppearanceButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:alpha="@dimen/volume_secondary_alpha"
         android:ellipsize="end"
         android:maxLines="1"
         android:paddingBottom="0dp"
@@ -50,8 +49,8 @@
         android:layout_below="@id/volume_row_header"
         android:layout_toEndOf="@id/volume_row_icon"
         android:layout_toStartOf="@+id/volume_settings_button"
-        android:paddingEnd="4dp"
-        android:paddingStart="4dp"
+        android:paddingEnd="8dp"
+        android:paddingStart="8dp"
         android:progressTint="@android:color/white"
         android:thumbTint="@android:color/white" />
 
diff --git a/packages/SystemUI/res/layout/volume_text_footer.xml b/packages/SystemUI/res/layout/volume_text_footer.xml
deleted file mode 100644
index 7436488..0000000
--- a/packages/SystemUI/res/layout/volume_text_footer.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/volume_text_footer"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:visibility="gone"
-    tools:ignore="UselessParent" >
-
-    <TextView
-        android:id="@+id/volume_footline_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/volume_footline_action_button"
-        android:alpha="@dimen/volume_secondary_alpha"
-        android:fontFamily="sans-serif"
-        android:paddingEnd="8dp"
-        android:paddingStart="13dp"
-        android:textColor="?android:attr/textColorPrimary" />
-
-    <Button
-        android:id="@+id/volume_footline_action_button"
-        style="@android:style/Widget.Material.Button.Borderless"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/volume_button_size"
-        android:layout_toEndOf="@id/volume_footline_text"
-        android:layout_toStartOf="@+id/volume_settings_button"
-        android:alpha="@dimen/volume_secondary_alpha"
-        android:paddingEnd="0dp"
-        android:paddingStart="0dp" />
-
-    <com.android.keyguard.AlphaOptimizedImageButton
-        android:id="@+id/volume_settings_button"
-        style="@style/VolumeButtons"
-        android:layout_width="@dimen/volume_button_size"
-        android:layout_height="@dimen/volume_button_size"
-        android:layout_alignParentEnd="true"
-        android:src="@drawable/ic_volume_settings" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index dcdc859..9e761e2 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -20,93 +20,58 @@
     android:layout_height="wrap_content"
     android:orientation="vertical" > <!-- extends LinearLayout -->
 
-    <LinearLayout
-        android:id="@+id/volume_zen_switch_bar"
+    <View
+        android:id="@+id/zen_embedded_divider"
         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" >
+        android:layout_height="1dp"
+        android:layout_marginBottom="8dp"
+        android:layout_marginTop="8dp"
+        android:background="#4dffffff" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="8dp"
+        android:paddingStart="8dp" >
 
         <ImageView
-            android:id="@+id/volume_zen_switch_bar_icon"
+            android:id="@+id/volume_zen_icon"
             android:layout_width="@dimen/volume_button_size"
             android:layout_height="@dimen/volume_button_size"
+            android:layout_marginEnd="7dp"
             android:scaleType="center"
             android:src="@drawable/ic_dnd" />
 
-        <TextView
+        <LinearLayout
             android:layout_width="0dp"
-            android:layout_height="fill_parent"
+            android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:gravity="center_vertical"
-            android:textDirection="locale"
-            android:padding="3dp"
-            android:text="@string/volume_zen_switch_text"
-            android:textAppearance="@style/TextAppearance.Volume.ZenSwitch" />
+            android:orientation="vertical" >
 
-        <Switch
-            android:id="@+id/volume_zen_switch"
-            android:layout_width="wrap_content"
-            android:layout_height="fill_parent"
-            android:layout_marginEnd="11dp" />
+            <TextView
+                android:id="@+id/volume_zen_summary_line_1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/TextAppearance.Volume.ZenSummary" />
 
-    </LinearLayout>
-
-    <RelativeLayout
-        android:id="@+id/volume_zen_panel_summary"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/volume_button_size"
-        android:layout_marginStart="@dimen/volume_button_size"
-        android:paddingEnd="7dp"
-        android:paddingStart="7dp" >
+            <TextView
+                android:id="@+id/volume_zen_summary_line_2"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/TextAppearance.Volume.ZenDetail" />
+        </LinearLayout>
 
         <TextView
-            android:id="@+id/volume_zen_panel_summary_line_1"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary" />
-
-        <TextView
-            android:id="@+id/volume_zen_panel_summary_line_2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/volume_zen_panel_summary_line_1"
-            android:textAppearance="@style/TextAppearance.Volume.ZenSwitchDetail" />
-    </RelativeLayout>
-
-    <include layout="@layout/zen_mode_panel" />
-
-    <LinearLayout
-        android:id="@+id/volume_zen_mode_panel_buttons"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
-        android:gravity="end" >
-
-        <TextView
-            android:id="@+id/volume_zen_mode_panel_more"
-            style="@style/QSBorderlessButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="8dp"
-            android:clickable="true"
-            android:focusable="true"
-            android:minWidth="132dp"
-            android:text="@string/quick_settings_more_settings"
-            android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
-        <TextView
-            android:id="@+id/volume_zen_mode_panel_done"
+            android:id="@+id/volume_zen_end_now"
             style="@style/QSBorderlessButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:clickable="true"
             android:focusable="true"
-            android:minWidth="66dp"
-            android:text="@string/quick_settings_done"
+            android:minWidth="91dp"
+            android:text="@string/volume_zen_end_now"
             android:textAppearance="@style/TextAppearance.QS.DetailButton" />
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index b676bce..595c9ed 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -22,81 +22,21 @@
     android:clipChildren="false"
     android:orientation="vertical" >
 
-    <FrameLayout
-        android:id="@+id/zen_buttons_container"
+    <com.android.systemui.volume.SegmentedButtons
+        android:id="@+id/zen_buttons"
         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" >
-
-        <com.android.systemui.volume.SegmentedButtons
-            android:id="@+id/zen_buttons"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
-            android:layout_marginBottom="8dp"
-            android:clipChildren="false" />
-    </FrameLayout>
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp" />
 
     <View
         android:id="@+id/zen_embedded_divider"
         android:layout_width="match_parent"
+        android:layout_marginTop="8dp"
         android:layout_height="1dp"
-        android:visibility="gone"
         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" >
-
-        <TextView
-            android:id="@+id/zen_subhead_collapsed"
-            android:layout_width="wrap_content"
-            android:layout_height="48dp"
-            android:layout_gravity="center_vertical"
-            android:gravity="center_vertical"
-            android:paddingLeft="8dp"
-            android:paddingRight="4dp"
-            android:background="@drawable/btn_borderless_rect"
-            android:clickable="true"
-            android:drawableEnd="@drawable/qs_subhead_caret"
-            android:maxLines="2"
-            android:ellipsize="end"
-            android:textAppearance="@style/TextAppearance.QS.Subhead" />
-
-        <TextView
-            android:id="@+id/zen_subhead_expanded"
-            android:layout_width="wrap_content"
-            android:layout_height="48dp"
-            android:layout_gravity="center_vertical"
-            android:gravity="center_vertical"
-            android:paddingLeft="8dp"
-            android:maxLines="2"
-            android:ellipsize="end"
-            android:textAppearance="@style/TextAppearance.QS.Subhead" />
-
-        <ImageView
-            android:id="@+id/zen_more_settings"
-            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_settings"
-            android:scaleType="center"
-            android:src="@drawable/ic_settings" />
-
-    </RelativeLayout>
-
-    <RelativeLayout
         android:id="@+id/zen_introduction"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -122,10 +62,9 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="12dp"
-            android:layout_marginStart="55dp"
+            android:layout_marginStart="24dp"
             android:lineSpacingMultiplier="1.20029"
             android:layout_toStartOf="@id/zen_introduction_confirm"
-            android:text="@string/zen_priority_introduction"
             android:textAppearance="@style/TextAppearance.QS.Introduction" />
 
         <TextView
@@ -141,6 +80,12 @@
             android:text="@string/zen_priority_customize_button"
             android:textAppearance="@style/TextAppearance.QS.DetailButton.White" />
 
+        <View
+            android:layout_width="0dp"
+            android:layout_height="16dp"
+            android:layout_below="@id/zen_introduction_message"
+            android:layout_alignParentEnd="true" />
+
     </RelativeLayout>
 
     <LinearLayout
@@ -149,7 +94,7 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="8dp"
         android:layout_marginEnd="4dp"
-        android:layout_marginStart="39dp"
+        android:layout_marginStart="4dp"
         android:orientation="vertical"
         android:paddingBottom="@dimen/zen_mode_condition_detail_bottom_padding" />
 
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2822445..70890b3 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -230,7 +230,7 @@
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ruutu on nyt lukittu vaakasuuntaan."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ruutu on nyt lukittu pystysuuntaan."</string>
     <string name="dessert_case" msgid="1295161776223959221">"Jälkiruokavitriini"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Unelmat"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Lepotila"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Älä häiritse"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Vain tärkeät"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index b0cc00a..97d6ba2 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -168,7 +168,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"स्क्रीन बन्द गर्नुहोस्।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिङहरू"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"सारांश।"</string>
-    <string name="accessibility_desc_confirm" msgid="3446792278337969766">"निश्चित गर्नुहोस्"</string>
+    <string name="accessibility_desc_confirm" msgid="3446792278337969766">"पुष्टि गर्नुहोस्"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"प्रयोगकर्ता <xliff:g id="USER">%s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"वाइफाइ बन्द गरियो।"</string>
@@ -303,7 +303,7 @@
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि माथि धिसार्नुहोस्"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"स्लाइड <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि बायाँ।"</string>
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"कुनै रुकावट छैन। चेतावनी समेत छैन।"</string>
-    <string name="zen_priority_introduction" msgid="7253045784560169993">"अलार्म, अनुस्मारक, घटनाहरु, र तपाईँले निर्दिष्ट कल देखि बाहेक, आवाज र कंपनले तपाईँ व्याकुल हुनुहुने छैन।"</string>
+    <string name="zen_priority_introduction" msgid="7253045784560169993">"अलार्म, रिमाइन्डर, घटना, र तपाईँले निर्दिष्ट गर्नुहुने कलरहरू बाहेक, आवाज र कंपनले तपाईँ वाधा गर्ने छैन।"</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"अनुकूलन गर्नुहोस्"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"कुनै रुकावटहरू छैन"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"प्राथमिकता रुकावटहरूमा मात्र"</string>
@@ -341,8 +341,8 @@
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"सुरु गर्नुहोस्"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"हो, जारी राख्नुहोस्"</string>
     <string name="guest_notification_title" msgid="1585278533840603063">"अतिथि प्रयोगकर्ता"</string>
-    <string name="guest_notification_text" msgid="7513706222848825467">"अनुप्रयोगहरू र डेटा मेटाउन अतिथिलाई निकाल्नु"</string>
-    <string name="guest_notification_remove_action" msgid="8820670703892101990">"REMOVE GUEST"</string>
+    <string name="guest_notification_text" msgid="7513706222848825467">"अनुप्रयोगहरू र डेटा मेटाउन अतिथिलाई निकाल्नुहोस्"</string>
+    <string name="guest_notification_remove_action" msgid="8820670703892101990">"अतिथिलाई हटाउनुहोस्"</string>
     <string name="user_add_user_title" msgid="4553596395824132638">"नयाँ प्रयोगकर्ता थप्नुहुन्छ?"</string>
     <string name="user_add_user_message_short" msgid="2161624834066214559">"जब तपाईँले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यस प्रयोगकर्ताले आफ्नो स्थान स्थापना गर्न पर्ने छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्।"</string>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ब्याट्रि सेभर चालु छ"</string>
@@ -362,13 +362,13 @@
     <string name="monitoring_title" msgid="169206259253048106">"सञ्जाल अनुगमन"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"VPN असक्षम गर्नुहोस्"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"विच्छेद VPN"</string>
-    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले सेटिङहरू, कर्पोरेट पहुँच, अनुप्रयोगहरू, आफ्नो उपकरण सम्बन्धित डेटा, र उपकरणको स्थानीय जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्छ। थप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।"</string>
-    <string name="monitoring_description_profile_owned" msgid="8110044290898637925">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासक इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।"</string>
-    <string name="monitoring_description_device_and_profile_owned" msgid="1664428184778531249">"तपाईँको उपकरण \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n तपाईँको कार्य प्रोफाइल \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो उपकरण र सञ्जाल गतिविधि अनुगमन गर्न सक्छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।"</string>
-    <string name="monitoring_description_vpn" msgid="912328761766161919">"तपाईँले VPN जडान गर्न अनुप्रयोगलाई अनुमति दिनुभयो।\n\nयो अनुप्रयोगले तपाईको यन्त्र र नेटवर्क गतिविधि,  इमेलहरु सम्मिलित, अनुप्रयोगहरू र सुरक्षित वेबसाइटहरू।"</string>
-    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले सेटिङ्हरू, कर्पोरेट पहुँच, अनुप्रयोगहरू, आफ्नो उपकरण सम्बन्धित डेटा, र उपकरणको स्थानीय जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्छ।\n\nतपाईँ VPN संग जडित हुनुहुन्छ, जसले तपाईँको इमेल, अनुप्रयोगहरू, र वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्छ। \n\nथप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2224494839524715272">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।\n\n तपाईँ VPN संग पनि जडित हुनुहुन्छ, जसले आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्छ।"</string>
-    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="2198546817407897093">"तपाईँको उपकरण <xliff:g id="ORGANIZATION_0">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\nतपाईँको कार्य प्रोफाइल \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासक इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासक संग सम्पर्क राख्नुहोस्।\n\n तपाईँ VPN संग पनि जडित हुनुहुन्छ, जसले आफ्नो व्यक्तिगत सञ्जाल गतिविधि अनुगमन गर्न सक्छ।"</string>
+    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"तपाईँको यन्त्र <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले सेटिङहरू, कर्पोरेट पहुँच, अनुप्रयोगहरू, आफ्नो उपकरण सम्बन्धित डेटा, र उपकरणको स्थानीय जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्छ। थप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।"</string>
+    <string name="monitoring_description_profile_owned" msgid="8110044290898637925">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासक इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासकससँग सम्पर्क राख्नुहोस्।"</string>
+    <string name="monitoring_description_device_and_profile_owned" msgid="1664428184778531249">"तपाईँको यन्त्र \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n तपाईँको कार्य प्रोफाइल \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो उपकरण र सञ्जाल गतिविधि अनुगमन गर्न सक्छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।"</string>
+    <string name="monitoring_description_vpn" msgid="912328761766161919">"तपाईँले VPN जडान गर्न अनुप्रयोगलाई अनुमति दिनुभयो।\n\nयो अनुप्रयोगले तपाईको यन्त्र र नेटवर्क गतिविधि,  इमेलहरु सम्मिलित, अनुप्रयोगहरू र सुरक्षित वेबसाइटहरूका अनुगमन गर्नसक्छ।"</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"तपाईँको यन्त्र <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले सेटिङ्हरू, कर्पोरेट पहुँच, अनुप्रयोगहरू, आफ्नो उपकरण सम्बन्धित डेटा, र उपकरणको स्थानीय जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्छ।\n\nतपाईँ VPN सँग जडित हुनुहुन्छ, जसले तपाईँको इमेल, अनुप्रयोगहरू, र वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्छ। \n\nथप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।"</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2224494839524715272">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासकले इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।\n\n तपाईँ VPN सँग पनि जडित हुनुहुन्छ, जसले आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्छ।"</string>
+    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="2198546817407897093">"तपाईँको यन्त्र <xliff:g id="ORGANIZATION_0">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\nतपाईँको कार्य प्रोफाइल \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ।\n\n तपाईँको प्रशासक इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू सहित आफ्नो सञ्जाल गतिविधि अनुगमन गर्न सक्षम छ।\n\n थप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।\n\n तपाईँ VPN सँग पनि जडित हुनुहुन्छ, जसले आफ्नो व्यक्तिगत सञ्जाल गतिविधि अनुगमन गर्न सक्छ।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"तपाईँले अनलक गर्नअघि तिनीहरूलाई हेर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1f1455a..7a108ed 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -128,7 +128,7 @@
     <color name="screen_pinning_request_window_bg">#80000000</color>
 
     <color name="segmented_button_selected">#FFFFFFFF</color>
-    <color name="segmented_button_unselected">#B3B0BEC5</color><!-- 70% blue grey 200 -->
+    <color name="segmented_button_unselected">#FFB0BEC5</color><!-- blue grey 200 -->
 
     <color name="dark_mode_icon_color_single_tone">#99000000</color>
     <color name="dark_mode_icon_color_dual_tone_background">#3d000000</color>
@@ -139,4 +139,6 @@
     <color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
 
     <color name="zen_introduction_message_background">#ff009688</color><!-- deep teal 500 -->
+    <color name="volume_icon_color">#ffffffff</color>
+    <color name="volume_settings_icon_color">#7fffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2e44547..6e79423 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -150,7 +150,7 @@
     <integer name="heads_up_notification_minimum_time">2000</integer>
 
     <!-- milliseconds before the heads up notification accepts touches. -->
-    <integer name="heads_up_sensitivity_delay">700</integer>
+    <integer name="touch_acceptance_delay">700</integer>
 
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
     <integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
@@ -293,5 +293,9 @@
 
     <!-- Duration of the full carrier network change icon animation. -->
     <integer name="carrier_network_change_anim_time">3000</integer>
+
+    <!-- Duration of the expansion animation in the volume dialog -->
+    <item name="volume_expand_animation_duration" type="integer">300</item>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6e59029..a0ef5e2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -573,4 +573,13 @@
 
     <!-- Minimum margin of the notification panel on the side, when being positioned dynamically -->
     <dimen name="notification_panel_min_side_margin">48dp</dimen>
+
+    <!-- Vertical spacing between multiple volume slider rows -->
+    <dimen name="volume_slider_interspacing">8dp</dimen>
+
+    <!-- Volume dialog vertical offset from the top of the screen -->
+    <dimen name="volume_offset_top">0dp</dimen>
+
+    <!-- Standard image button size for volume dialog buttons -->
+    <dimen name="volume_button_size">48dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fe49ef6..00b8df2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -441,7 +441,7 @@
     <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
     <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+    <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, total silence.</string>
     <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_alarms_on">Do not disturb on, alarms only.</string>
      <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -578,8 +578,8 @@
     <string name="quick_settings_dnd_priority_label">Priority only</string>
     <!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_alarms_label">Alarms only</string>
-    <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_dnd_none_label">No interruptions</string>
+    <!-- QuickSettings: Do not disturb - Total silence [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_none_label">Total silence</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
     <string name="quick_settings_bluetooth_label">Bluetooth</string>
     <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
@@ -727,32 +727,14 @@
     <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
 
-    <!-- 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>
+    <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>
-
-    <!-- Zen mode: Only important interruptions. [CHAR LIMIT=40] -->
-    <string name="zen_important_interruptions">Priority interruptions only</string>
-
-    <!-- Zen mode: Only alarms. [CHAR LIMIT=40] -->
-    <string name="zen_alarms">Alarms only</string>
-
-    <!-- Zen mode: Next alarm information - just a time. [CHAR LIMIT=40] -->
-    <string name="zen_alarm_information_time">Your next alarm is at <xliff:g id="alarm_time" example="5:00 PM">%s</xliff:g></string>
-
-    <!-- Zen mode: Next alarm information - day and time. [CHAR LIMIT=40] -->
-    <string name="zen_alarm_information_day_time">Your next alarm is <xliff:g id="alarm_day_and_time" example="Fri 5:00 PM">%s</xliff:g></string>
-
-    <!-- Zen mode: Next alarm warning. [CHAR LIMIT=40] -->
-    <string name="zen_alarm_warning">You won\'t hear your alarm at <xliff:g id="alarm_time" example="5:00 PM">%s</xliff:g></string>
+    <!-- Zen mode: Total silence introduction message on first use -->
+    <string name="zen_silence_introduction">This blocks ALL sounds and vibrations, including from alarms, music, videos, and games. You’ll still be able to make phone calls.</string>
 
     <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
     <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
@@ -772,25 +754,22 @@
     <!-- Shows when people have clicked at the right edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] -->
     <string name="camera_hint">Swipe left for camera</string>
 
-    <!-- Interruption level: None. [CHAR LIMIT=20] -->
-    <string name="interruption_level_none">No interruptions</string>
+    <!-- Interruption level: None. [CHAR LIMIT=40] -->
+    <string name="interruption_level_none">Total silence</string>
 
-    <!-- Interruption level: Priority. [CHAR LIMIT=20] -->
+    <!-- Interruption level: Priority. [CHAR LIMIT=40] -->
     <string name="interruption_level_priority">Priority only</string>
 
-    <!-- Interruption level: Alarms only. [CHAR LIMIT=20] -->
+    <!-- Interruption level: Alarms only. [CHAR LIMIT=40] -->
     <string name="interruption_level_alarms">Alarms only</string>
 
-    <!-- Interruption level: All. [CHAR LIMIT=20] -->
-    <string name="interruption_level_all">All</string>
+    <!-- Interruption level: None.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
+    <string name="interruption_level_none_twoline">Total\nsilence</string>
 
-    <!-- Interruption level: None.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
-    <string name="interruption_level_none_twoline">No\ninterruptions</string>
-
-    <!-- Interruption level: Priority.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
+    <!-- Interruption level: Priority.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
     <string name="interruption_level_priority_twoline">Priority\nonly</string>
 
-    <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
+    <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
     <string name="interruption_level_alarms_twoline">Alarms\nonly</string>
 
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
@@ -913,23 +892,32 @@
     <!-- Monitoring dialog device owner body text [CHAR LIMIT=400] -->
     <string name="monitoring_description_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information. For more information, contact your administrator.</string>
 
-    <!-- Monitoring dialog profile owner body text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
-
-    <!-- Monitoring dialog device and profile owner body text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_device_and_profile_owned">Your device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>.\nYour work profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>.\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
-
     <!-- Monitoring dialog VPN text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and secure websites.</string>
+    <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites.</string>
 
     <!-- Monitoring dialog VPN with device owner text [CHAR LIMIT=400] -->
     <string name="monitoring_description_vpn_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to a VPN, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
 
     <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
+    <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
 
-    <!-- Monitoring dialog VPN with device and profile owner text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn_device_and_profile_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\nYour work profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your personal network activity</string>
+    <!-- Name for a generic legacy VPN connection [CHAR LIMIT=20] -->
+    <string name="legacy_vpn_name">VPN</string>
+
+    <!-- Monitoring dialog text for single app (no profile or device owner) [CHAR LIMIT=400] -->
+    <string name="monitoring_description_app">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites.</string>
+
+    <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
+    <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites.</string>
+
+    <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
+    <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator.</string>
+
+    <!-- Monitoring dialog text for multiple apps (in personal and work profiles) [CHAR LIMIT=400] -->
+    <string name="monitoring_description_app_personal_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application_work">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="application_personal">%3$s</xliff:g>, which can monitor your personal network activity.</string>
+
+    <!-- Monitoring dialog text for single app (with device owner) [CHAR LIMIT=400] -->
+    <string name="monitoring_description_vpn_app_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
 
     <!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
     <string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
@@ -955,6 +943,9 @@
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
+    <!-- Button label for ending zen mode in the volume dialog -->
+    <string name="volume_zen_end_now">End now</string>
+
     <!-- Screen pinning dialog title. -->
     <string name="screen_pinning_title">Screen is pinned</string>
     <!-- Screen pinning dialog description. -->
@@ -990,9 +981,26 @@
     <!-- VolumeUI restoration notification: text -->
     <string name="volumeui_notification_text">Touch to restore the original.</string>
 
-    <!-- Volume dialog zen toggle switch title -->
-    <string name="volume_zen_switch_text" translatable="false">@*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>
+
+    <string-array name="volume_stream_titles" translatable="false">
+        <item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
+        <item>System</item> <!-- STREAM_SYSTEM -->
+        <item>Notifications</item> <!-- STREAM_RING -->
+        <item>Media</item> <!-- STREAM_MUSIC -->
+        <item>Alarms</item> <!-- STREAM_ALARM -->
+        <item></item> <!-- STREAM_NOTIFICATION -->
+        <item>Bluetooth calls</item> <!-- STREAM_BLUETOOTH_SCO -->
+        <item></item> <!-- STREAM_SYSTEM_ENFORCED -->
+        <item></item> <!-- STREAM_DTMF -->
+        <item></item> <!-- STREAM_TTS -->
+    </string-array>
+
+    <string name="volume_stream_muted" translatable="false">%s silent</string>
+    <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
+    <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
+    <string name="volume_stream_muted_dnd" translatable="false">%s silent — Total silence</string>
+    <string name="volume_stream_limited_dnd" translatable="false">%s — Priority only</string>
+    <string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ef2e6f3..c058d44 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -165,7 +165,7 @@
     </style>
 
     <style name="TextAppearance.QS.SegmentedButton">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">16sp</item>
     </style>
 
     <style name="TextAppearance.QS.DataUsage">
@@ -262,4 +262,31 @@
         <item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
         <item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
     </style>
+
+    <style name="TextAppearance.Volume">
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffffff</item>
+        <item name="android:fontFamily">sans-serif</item>
+    </style>
+
+    <style name="TextAppearance.Volume.ZenSummary">
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.Volume.ZenDetail">
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textColor">#ffb0b3c5</item>
+    </style>
+
+    <style name="VolumeDialogAnimations">
+        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
+        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+    </style>
+
+    <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
+        <item name="android:background">@drawable/btn_borderless_rect</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/values/volume.xml b/packages/SystemUI/res/values/volume.xml
deleted file mode 100644
index f516104..0000000
--- a/packages/SystemUI/res/values/volume.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item name="volume_expand_animation_duration" type="integer">300</item>
-
-    <color name="volume_icon_color">#ffffffff</color>
-    <color name="volume_settings_icon_color">#7fffffff</color>
-
-    <dimen name="volume_slider_interspacing">2dp</dimen>
-    <dimen name="volume_offset_top">0dp</dimen>
-    <dimen name="volume_button_size">48dp</dimen>
-
-    <item name="volume_secondary_alpha" format="float" type="dimen">0.3</item>
-
-    <style name="VolumeDialogAnimations">
-        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
-        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
-    </style>
-
-    <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
-        <item name="android:background">@drawable/btn_borderless_rect</item>
-    </style>
-
-    <style name="TextAppearance" />
-
-    <style name="TextAppearance.Volume">
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#ffffffff</item>
-        <item name="android:fontFamily">sans-serif</item>
-    </style>
-
-    <style name="TextAppearance.Volume.ZenSwitch">
-        <item name="android:textSize">16sp</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
-    </style>
-
-    <style name="TextAppearance.Volume.ZenSwitchSummary">
-        <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
-    </style>
-
-    <style name="TextAppearance.Volume.ZenSwitchDetail">
-        <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif</item>
-        <item name="android:textColor">#ffb0b3c5</item>
-    </style>
-
-    <string-array name="volume_stream_titles" translatable="false">
-        <item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
-        <item>System</item> <!-- STREAM_SYSTEM -->
-        <item>Notifications</item> <!-- STREAM_RING -->
-        <item>Media</item> <!-- STREAM_MUSIC -->
-        <item>Alarms</item> <!-- STREAM_ALARM -->
-        <item></item> <!-- STREAM_NOTIFICATION -->
-        <item>Bluetooth calls</item> <!-- STREAM_BLUETOOTH_SCO -->
-        <item></item> <!-- STREAM_SYSTEM_ENFORCED -->
-        <item></item> <!-- STREAM_DTMF -->
-        <item></item> <!-- STREAM_TTS -->
-    </string-array>
-
-    <string name="volume_dnd_is_on" translatable="false">Do not disturb is on</string>
-    <string name="volume_turn_off" translatable="false">Turn off</string>
-    <string name="volume_stream_muted" translatable="false">%s silent</string>
-    <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
-    <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
-    <string name="volume_stream_muted_dnd" translatable="false">%s silent — No interruptions</string>
-    <string name="volume_stream_limited_dnd" translatable="false">%s — Priority only</string>
-    <string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
-    <string name="volume_dnd_ends_in" translatable="false">Do not disturb ends in %s</string>
-    <string name="volume_dnd_ends_at" translatable="false">Do not disturb ends at %s</string>
-    <string name="volume_end_now" translatable="false">End now</string>
-
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0d331d1..3fbc76b 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -225,23 +225,23 @@
         mSubpixelSmoothingRight = context.getResources().getFraction(
                 R.fraction.battery_subpixel_smoothing_right, 1, 1);
 
-        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFramePaint = new Paint();
         mFramePaint.setColor(frameColor);
         mFramePaint.setDither(true);
         mFramePaint.setStrokeWidth(0);
         mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
-        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBatteryPaint = new Paint();
         mBatteryPaint.setDither(true);
         mBatteryPaint.setStrokeWidth(0);
         mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
-        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint = new Paint();
         Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
         mTextPaint.setTypeface(font);
         mTextPaint.setTextAlign(Paint.Align.CENTER);
 
-        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mWarningTextPaint = new Paint();
         mWarningTextPaint.setColor(mColors[1]);
         font = Typeface.create("sans-serif", Typeface.BOLD);
         mWarningTextPaint.setTypeface(font);
@@ -249,7 +249,7 @@
 
         mChargeColor = context.getColor(R.color.batterymeter_charge_color);
 
-        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBoltPaint = new Paint();
         mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
         mBoltPoints = loadBoltPoints(res);
 
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 68b1968..29d2a01 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -37,8 +37,10 @@
         Key.DND_TILE_VISIBLE,
         Key.DND_TILE_COMBINED_ICON,
         Key.DND_CONFIRMED_PRIORITY_INTRODUCTION,
+        Key.DND_CONFIRMED_SILENCE_INTRODUCTION,
         Key.DND_FAVORITE_BUCKET_INDEX,
         Key.DND_NONE_SELECTED,
+        Key.DND_FAVORITE_ZEN,
     })
     public @interface Key {
         String SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
@@ -48,8 +50,10 @@
         String DND_TILE_VISIBLE = "DndTileVisible";
         String DND_TILE_COMBINED_ICON = "DndTileCombinedIcon";
         String DND_CONFIRMED_PRIORITY_INTRODUCTION = "DndConfirmedPriorityIntroduction";
+        String DND_CONFIRMED_SILENCE_INTRODUCTION = "DndConfirmedSilenceIntroduction";
         String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex";
         String DND_NONE_SELECTED = "DndNoneSelected";
+        String DND_FAVORITE_ZEN = "DndFavoriteZen";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7b555fc..6479dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -539,10 +539,11 @@
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
 
         mLockPatternUtils = new LockPatternUtils(mContext);
-        mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
+        KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
 
         // Assume keyguard is showing (unless it's disabled) until we know for sure...
-        setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled());
+        setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(
+                KeyguardUpdateMonitor.getCurrentUser()));
         mTrustManager.reportKeyguardShowingChanged();
 
         mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext,
@@ -623,8 +624,10 @@
             // Lock immediately based on setting if secure (user has a pin/pattern/password).
             // This also "locks" the device when not secure to provide easy access to the
             // camera while preventing unwanted input.
+            int currentUser = KeyguardUpdateMonitor.getCurrentUser();
             final boolean lockImmediately =
-                mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
+                mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
+                        || !mLockPatternUtils.isSecure(currentUser);
 
             notifyScreenOffLocked();
 
@@ -670,7 +673,7 @@
 
         // From DevicePolicyAdmin
         final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
-                .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
+                .getMaximumTimeToLock(null, KeyguardUpdateMonitor.getCurrentUser());
 
         long timeout;
         if (policyTimeout > 0) {
@@ -719,7 +722,8 @@
     }
 
     private void maybeSendUserPresentBroadcast() {
-        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()) {
+        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled(
+                KeyguardUpdateMonitor.getCurrentUser())) {
             // Lock screen is disabled because the user has set the preference to "None".
             // In this case, send out ACTION_USER_PRESENT here instead of in
             // handleKeyguardDone()
@@ -733,7 +737,7 @@
      */
     public void onDreamingStarted() {
         synchronized (this) {
-            if (mScreenOn && mLockPatternUtils.isSecure()) {
+            if (mScreenOn && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
                 doKeyguardLaterLocked();
             }
         }
@@ -974,12 +978,13 @@
             return;
         }
 
-        if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {
+        if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
+                && !lockedOrMissing) {
             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
             return;
         }
 
-        if (mLockPatternUtils.checkVoldPassword()) {
+        if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
             if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
             // Without this, settings is not enabled until the lock screen first appears
             setShowingLocked(false);
@@ -1072,7 +1077,7 @@
     }
 
     public boolean isSecure() {
-        return mLockPatternUtils.isSecure()
+        return mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())
             || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
     }
 
@@ -1083,7 +1088,7 @@
      * @param newUserId The id of the incoming user.
      */
     public void setCurrentUser(int newUserId) {
-        mLockPatternUtils.setCurrentUser(newUserId);
+        KeyguardUpdateMonitor.setCurrentUser(newUserId);
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -1213,7 +1218,7 @@
     private void sendUserPresentBroadcast() {
         synchronized (this) {
             if (mBootCompleted) {
-                final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+                final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser());
                 final UserManager um = (UserManager) mContext.getSystemService(
                         Context.USER_SERVICE);
                 List <UserInfo> userHandles = um.getProfiles(currentUser.getIdentifier());
@@ -1393,14 +1398,9 @@
             updateActivityLockScreenState();
             adjustStatusBarLocked();
             sendUserPresentBroadcast();
-            maybeStopListeningForFingerprint();
         }
     }
 
-    private void maybeStopListeningForFingerprint() {
-        mUpdateMonitor.stopListeningForFingerprint();
-    }
-
     private void adjustStatusBarLocked() {
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index d8e3984..f59e864 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -110,21 +110,15 @@
     }
 
     private void handleRefreshState() {
-        if (mSecurityController.hasDeviceOwner()) {
+        boolean hasDeviceOwner = mSecurityController.hasDeviceOwner();
+        boolean hasVpn = mSecurityController.isVpnEnabled();
+
+        mIsVisible = (hasVpn || hasDeviceOwner);
+        mIsIconVisible = hasVpn;
+        if (hasDeviceOwner) {
             mFooterTextId = R.string.device_owned_footer;
-            mIsVisible = true;
-            mIsIconVisible = false;
-        } else if (mSecurityController.hasProfileOwner()) {
-            mFooterTextId = R.string.profile_owned_footer;
-            mIsVisible = true;
-            mIsIconVisible = false;
-        } else if (mSecurityController.isVpnEnabled()) {
-            mFooterTextId = R.string.vpn_footer;
-            mIsVisible = true;
-            mIsIconVisible = true;
         } else {
-            mIsVisible = false;
-            mIsIconVisible = false;
+            mFooterTextId = R.string.vpn_footer;
         }
         mMainHandler.post(mUpdateDisplayState);
     }
@@ -162,37 +156,17 @@
 
     private String getMessage(boolean hasDeviceOwner, boolean hasProfile, boolean hasVpn) {
         if (hasDeviceOwner) {
-            if (hasProfile) {
-                if (hasVpn) {
-                    return mContext.getString(
-                            R.string.monitoring_description_vpn_device_and_profile_owned,
-                            mSecurityController.getDeviceOwnerName(),
-                            mSecurityController.getProfileOwnerName());
-                } else {
-                    return mContext.getString(
-                            R.string.monitoring_description_device_and_profile_owned,
-                            mSecurityController.getDeviceOwnerName(),
-                            mSecurityController.getProfileOwnerName());
-                }
+            if (hasVpn) {
+                return mContext.getString(R.string.monitoring_description_vpn_device_owned,
+                        mSecurityController.getDeviceOwnerName());
             } else {
-                if (hasVpn) {
-                    return mContext.getString(R.string.monitoring_description_vpn_device_owned,
-                            mSecurityController.getDeviceOwnerName());
-                } else {
-                    return mContext.getString(R.string.monitoring_description_device_owned,
-                            mSecurityController.getDeviceOwnerName());
-                }
+                return mContext.getString(R.string.monitoring_description_device_owned,
+                        mSecurityController.getDeviceOwnerName());
             }
         } else if (hasProfile) {
-            if (hasVpn) {
-                return mContext.getString(
-                        R.string.monitoring_description_vpn_profile_owned,
-                        mSecurityController.getProfileOwnerName());
-            } else {
-                return mContext.getString(
-                        R.string.monitoring_description_profile_owned,
-                        mSecurityController.getProfileOwnerName());
-            }
+            return mContext.getString(
+                    R.string.monitoring_description_vpn_profile_owned,
+                    mSecurityController.getProfileOwnerName());
         } else {
             return mContext.getString(R.string.monitoring_description_vpn);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 6ce63d6..5145bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -37,7 +37,11 @@
 
 /** Quick settings tile: Do not disturb **/
 public class DndTile extends QSTile<QSTile.BooleanState> {
-    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+    private static final Intent ZEN_SETTINGS =
+            new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private static final Intent ZEN_PRIORITY_SETTINGS =
+            new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
 
     private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
     private static final String EXTRA_VISIBLE = "visible";
@@ -87,7 +91,9 @@
         if (mState.value) {
             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
         } else {
-            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
+            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
+            mController.setZen(zen, null, TAG);
+            refreshState(zen); // this one's optimistic
             showDetail(true);
         }
     }
@@ -209,8 +215,8 @@
                             R.layout.zen_mode_panel, parent, false);
             if (convertView == null) {
                 zmp.init(mController);
-                zmp.setEmbedded(true);
                 zmp.addOnAttachStateChangeListener(this);
+                zmp.setCallback(mZenModePanelCallback);
             }
             return zmp;
         }
@@ -225,4 +231,22 @@
             mShowingDetail = false;
         }
     }
+
+    private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
+        @Override
+        public void onPrioritySettings() {
+            mHost.startSettingsActivity(ZEN_PRIORITY_SETTINGS);
+        }
+
+        @Override
+        public void onInteraction() {
+            // noop
+        }
+
+        @Override
+        public void onExpanded(boolean expanded) {
+            // noop
+        }
+    };
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7271469..26c3b4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -87,6 +87,7 @@
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SwipeHelper;
@@ -639,7 +640,7 @@
                 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
             Log.d(TAG, "user hasn't seen notification about hidden notifications");
             final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
-            if (!lockPatternUtils.isSecure()) {
+            if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
                 Log.d(TAG, "insecure lockscreen, skipping notification");
                 Settings.Secure.putInt(mContext.getContentResolver(),
                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -708,18 +709,6 @@
         mNotificationListener.setNotificationsShown(keys);
     }
 
-    protected void setNotificationsShownAll() {
-        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
-        final int N = activeNotifications.size();
-
-        String[] keys = new String[N];
-        for (int i = 0; i < N; i++) {
-            NotificationData.Entry entry = activeNotifications.get(i);
-            keys[i] = entry.key;
-        }
-        setNotificationsShown(keys);
-    }
-
     protected boolean isCurrentProfile(int userId) {
         synchronized (mCurrentProfiles) {
             return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
@@ -795,7 +784,8 @@
     protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
             NotificationData.Entry entry) {
 
-        if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
+        if (entry.getContentView().getId()
+                != com.android.internal.R.id.status_bar_latest_event_content) {
             // Using custom RemoteViews
             if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
                     && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
@@ -820,8 +810,9 @@
 
     public boolean isMediaNotification(NotificationData.Entry entry) {
         // TODO: confirm that there's a valid media key
-        return entry.expandedBig != null &&
-               entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null;
+        return entry.getExpandedContentView() != null &&
+               entry.getExpandedContentView()
+                       .findViewById(com.android.internal.R.id.media_actions) != null;
     }
 
     // The gear button in the guts that links to the app's own notification settings
@@ -1145,9 +1136,9 @@
     }
 
     /**
-     * if the interrupting notification had a fullscreen intent, fire it now.
+     * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
      */
-    public abstract void escalateHeadsUp();
+    public abstract void maybeEscalateHeadsUp();
 
     /**
      * Save the current "public" (locked and secure) state of the lockscreen.
@@ -1348,8 +1339,8 @@
         View publicViewLocal = null;
         if (publicNotification != null) {
             try {
-                publicViewLocal = publicNotification.contentView.apply(mContext, contentContainerPublic,
-                        mOnClickHandler);
+                publicViewLocal = publicNotification.contentView.apply(mContext,
+                        contentContainerPublic, mOnClickHandler);
 
                 if (publicViewLocal != null) {
                     publicViewLocal.setIsRootNamespace(true);
@@ -1456,9 +1447,7 @@
         entry.row = row;
         entry.row.setHeightRange(mRowMinHeight, maxHeight);
         entry.row.setOnActivatedListener(this);
-        entry.expanded = contentViewLocal;
-        entry.expandedPublic = publicViewLocal;
-        entry.setBigContentView(bigContentViewLocal);
+        entry.row.setExpandable(bigContentViewLocal != null);
 
         applyColorsAndBackgrounds(sbn, entry);
 
@@ -1547,12 +1536,13 @@
 
         // See if we have somewhere to put that remote input
         if (remoteInput != null) {
-            if (entry.expandedBig != null) {
-                inflateRemoteInput(entry.expandedBig, remoteInput, actions);
+            View bigContentView = entry.getExpandedContentView();
+            if (bigContentView != null) {
+                inflateRemoteInput(bigContentView, remoteInput, actions);
             }
-            View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild();
-            if (headsUpChild != null) {
-                inflateRemoteInput(headsUpChild, remoteInput, actions);
+            View headsUpContentView = entry.getHeadsUpContentView();
+            if (headsUpContentView != null) {
+                inflateRemoteInput(headsUpContentView, remoteInput, actions);
             }
         }
 
@@ -1701,7 +1691,6 @@
                 boolean clearNotificationEffects =
                         (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
                 mBarService.onPanelRevealed(clearNotificationEffects);
-                setNotificationsShownAll();
             } else {
                 mBarService.onPanelHidden();
             }
@@ -1895,15 +1884,14 @@
             logUpdate(entry, n);
         }
         boolean applyInPlace = shouldApplyInPlace(entry, n);
-        final boolean shouldInterrupt = shouldInterrupt(notification);
-        final boolean alertAgain = alertAgain(entry, n);
+        boolean shouldInterrupt = shouldInterrupt(notification);
+        boolean alertAgain = alertAgain(entry, n);
 
         entry.notification = notification;
         mGroupManager.onEntryUpdated(entry, entry.notification);
 
         boolean updateSuccessful = false;
         if (applyInPlace) {
-            // We can just reapply the notifications in place
             if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
             try {
                 if (entry.icon != null) {
@@ -1924,7 +1912,7 @@
                 updateSuccessful = true;
             }
             catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
+                // It failed to apply cleanly.
                 Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
             }
         }
@@ -1948,11 +1936,12 @@
         // swipe-dismissable)
         updateNotificationVetoButton(entry.row, notification);
 
-        // Is this for you?
-        boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
-        if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+        if (DEBUG) {
+            // Is this for you?
+            boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
+            Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+        }
 
-        // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
     }
 
@@ -1963,7 +1952,7 @@
         StatusBarNotification oldNotification = oldEntry.notification;
         Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
                 + " ongoing=" + oldNotification.isOngoing()
-                + " expanded=" + oldEntry.expanded
+                + " expanded=" + oldEntry.getContentView()
                 + " contentView=" + oldNotification.getNotification().contentView
                 + " bigContentView=" + oldNotification.getNotification().bigContentView
                 + " publicView=" + oldNotification.getNotification().publicVersion
@@ -1976,7 +1965,8 @@
     }
 
     /**
-     * @return whether we can just reapply the RemoteViews in place when it is updated
+     * @return whether we can just reapply the RemoteViews from a notification in-place when it is
+     * updated
      */
     private boolean shouldApplyInPlace(Entry entry, Notification n) {
         StatusBarNotification oldNotification = entry.notification;
@@ -1994,15 +1984,15 @@
         final Notification publicNotification = n.publicVersion;
         final RemoteViews publicContentView = publicNotification != null
                 ? publicNotification.contentView : null;
-        boolean contentsUnchanged = entry.expanded != null
+        boolean contentsUnchanged = entry.getContentView() != null
                 && contentView.getPackage() != null
                 && oldContentView.getPackage() != null
                 && oldContentView.getPackage().equals(contentView.getPackage())
                 && oldContentView.getLayoutId() == contentView.getLayoutId();
         // large view may be null
         boolean bigContentsUnchanged =
-                (entry.getBigContentView() == null && bigContentView == null)
-                || ((entry.getBigContentView() != null && bigContentView != null)
+                (entry.getExpandedContentView() == null && bigContentView == null)
+                || ((entry.getExpandedContentView() != null && bigContentView != null)
                     && bigContentView.getPackage() != null
                     && oldBigContentView.getPackage() != null
                     && oldBigContentView.getPackage().equals(bigContentView.getPackage())
@@ -2034,12 +2024,12 @@
                 : null;
 
         // Reapply the RemoteViews
-        contentView.reapply(mContext, entry.expanded, mOnClickHandler);
-        if (bigContentView != null && entry.getBigContentView() != null) {
-            bigContentView.reapply(mContext, entry.getBigContentView(),
+        contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
+        if (bigContentView != null && entry.getExpandedContentView() != null) {
+            bigContentView.reapply(mContext, entry.getExpandedContentView(),
                     mOnClickHandler);
         }
-        View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild();
+        View headsUpChild = entry.getHeadsUpContentView();
         if (headsUpContentView != null && headsUpChild != null) {
             headsUpContentView.reapply(mContext, headsUpChild, mOnClickHandler);
         }
@@ -2062,7 +2052,7 @@
     }
 
     protected void notifyHeadsUpScreenOff() {
-        escalateHeadsUp();
+        maybeEscalateHeadsUp();
     }
 
     private boolean alertAgain(Entry oldEntry, Notification newNotification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index cb8217e..9ef495d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -84,7 +84,6 @@
     private ExpansionLogger mLogger;
     private String mLoggingKey;
     private boolean mWasReset;
-
     private NotificationGuts mGuts;
     private StatusBarNotification mStatusBarNotification;
     private boolean mIsHeadsUp;
@@ -102,6 +101,7 @@
     private ViewStub mGutsStub;
     private boolean mHasExpandAction;
     private boolean mIsSystemChildExpanded;
+    private boolean mIsPinned;
     private OnClickListener mExpandClickListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -109,7 +109,6 @@
                     !mChildrenExpanded);
         }
     };
-    private boolean mInShade;
 
     public NotificationContentView getPrivateLayout() {
         return mPrivateLayout;
@@ -284,12 +283,18 @@
         return realActualHeight;
     }
 
-    public void setInShade(boolean inShade) {
-        mInShade = inShade;
+    /**
+     * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
+     * the notification will be rendered on top of the screen.
+     *
+     * @param pinned whether it is pinned
+     */
+    public void setPinned(boolean pinned) {
+        mIsPinned = pinned;
     }
 
-    public boolean isInShade() {
-        return mInShade;
+    public boolean isPinned() {
+        return mIsPinned;
     }
 
     public int getHeadsUpHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 1c53655..110b14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -32,37 +32,34 @@
 import com.android.systemui.R;
 
 /**
- * A frame layout containing the actual payload of the notification, including the contracted and
- * expanded layout. This class is responsible for clipping the content and and switching between the
- * expanded and contracted view depending on its clipped size.
+ * A frame layout containing the actual payload of the notification, including the contracted,
+ * expanded and heads up layout. This class is responsible for clipping the content and and
+ * switching between the expanded, contracted and the heads up view depending on its clipped size.
  */
 public class NotificationContentView extends FrameLayout {
 
     private static final long ANIMATION_DURATION_LENGTH = 170;
-    private static final int CONTRACTED = 1;
-    private static final int EXPANDED = 2;
-    private static final int HEADSUP = 3;
+    private static final int VISIBLE_TYPE_CONTRACTED = 0;
+    private static final int VISIBLE_TYPE_EXPANDED = 1;
+    private static final int VISIBLE_TYPE_HEADSUP = 2;
 
     private final Rect mClipBounds = new Rect();
+    private final int mSmallHeight;
+    private final int mHeadsUpHeight;
+    private final Interpolator mLinearInterpolator = new LinearInterpolator();
 
     private View mContractedChild;
     private View mExpandedChild;
     private View mHeadsUpChild;
 
     private NotificationViewWrapper mContractedWrapper;
-
-    private final int mSmallHeight;
-    private final int mHeadsUpHeight;
     private int mClipTopAmount;
-
     private int mContentHeight;
-
-    private final Interpolator mLinearInterpolator = new LinearInterpolator();
-    private int mVisibleView = CONTRACTED;
-
+    private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
     private boolean mDark;
     private final Paint mFadePaint = new Paint();
     private boolean mAnimate;
+    private boolean mIsHeadsUp;
     private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
@@ -72,7 +69,6 @@
             return true;
         }
     };
-    private boolean mIsHeadsUp;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -105,9 +101,9 @@
                 // An actual height is set
                 size = Math.min(maxSize, layoutParams.height);
             }
-            int spec = size == Integer.MAX_VALUE ?
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
-                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+            int spec = size == Integer.MAX_VALUE
+                    ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+                    : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
             mExpandedChild.measure(widthMeasureSpec, spec);
             maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
         }
@@ -153,7 +149,7 @@
         mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
-        mVisibleView = CONTRACTED;
+        mVisibleType = VISIBLE_TYPE_CONTRACTED;
         if (resetActualHeight) {
             mContentHeight = mSmallHeight;
         }
@@ -263,30 +259,32 @@
         if (mContractedChild == null) {
             return;
         }
-        int visibleView = calculateVisibleView();
-        if (visibleView != mVisibleView || force) {
-            if (animate && mExpandedChild != null) {
-                runSwitchAnimation(visibleView);
+        int visibleType = calculateVisibleType();
+        if (visibleType != mVisibleType || force) {
+            if (animate && (visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
+                    || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
+                    || visibleType == VISIBLE_TYPE_CONTRACTED) {
+                runSwitchAnimation(visibleType);
             } else {
-                updateViewVisibilities(visibleView);
+                updateViewVisibilities(visibleType);
             }
-            mVisibleView = visibleView;
+            mVisibleType = visibleType;
         }
     }
 
-    private void updateViewVisibilities(int visibleView) {
-        boolean contractedVisible = visibleView == CONTRACTED;
+    private void updateViewVisibilities(int visibleType) {
+        boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
         mContractedChild.setVisibility(contractedVisible ? View.VISIBLE : View.INVISIBLE);
         mContractedChild.setAlpha(contractedVisible ? 1f : 0f);
         mContractedChild.setLayerType(LAYER_TYPE_NONE, null);
         if (mExpandedChild != null) {
-            boolean expandedVisible = visibleView == EXPANDED;
+            boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
             mExpandedChild.setVisibility(expandedVisible ? View.VISIBLE : View.INVISIBLE);
             mExpandedChild.setAlpha(expandedVisible ? 1f : 0f);
             mExpandedChild.setLayerType(LAYER_TYPE_NONE, null);
         }
         if (mHeadsUpChild != null) {
-            boolean headsUpVisible = visibleView == HEADSUP;
+            boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
             mHeadsUpChild.setVisibility(headsUpVisible ? View.VISIBLE : View.INVISIBLE);
             mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
             mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
@@ -294,9 +292,9 @@
         setLayerType(LAYER_TYPE_NONE, null);
     }
 
-    private void runSwitchAnimation(int visibleView) {
-        View shownView = getViewFromFlag(visibleView);
-        View hiddenView = getViewFromFlag(mVisibleView);
+    private void runSwitchAnimation(int visibleType) {
+        View shownView = getViewForVisibleType(visibleType);
+        View hiddenView = getViewForVisibleType(mVisibleType);
         shownView.setVisibility(View.VISIBLE);
         hiddenView.setVisibility(View.VISIBLE);
         shownView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
@@ -314,34 +312,42 @@
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
-                        updateViewVisibilities(mVisibleView);
+                        updateViewVisibilities(mVisibleType);
                     }
                 });
     }
 
-    private View getViewFromFlag(int visibleView) {
-        switch (visibleView) {
-            case EXPANDED:
+    /**
+     * @param visibleType one of the static enum types in this view
+     * @return the corresponding view according to the given visible type
+     */
+    private View getViewForVisibleType(int visibleType) {
+        switch (visibleType) {
+            case VISIBLE_TYPE_EXPANDED:
                 return mExpandedChild;
-            case HEADSUP:
+            case VISIBLE_TYPE_HEADSUP:
                 return mHeadsUpChild;
+            default:
+                return mContractedChild;
         }
-        return mContractedChild;
     }
 
-    private int calculateVisibleView() {
+    /**
+     * @return one of the static enum types in this view, calculated form the current state
+     */
+    private int calculateVisibleType() {
         boolean noExpandedChild = mExpandedChild == null;
         if (mIsHeadsUp && mHeadsUpChild != null) {
             if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
-                return HEADSUP;
+                return VISIBLE_TYPE_HEADSUP;
             } else {
-                return EXPANDED;
+                return VISIBLE_TYPE_EXPANDED;
             }
         } else {
             if (mContentHeight <= mSmallHeight || noExpandedChild) {
-                return CONTRACTED;
+                return VISIBLE_TYPE_CONTRACTED;
             } else {
-                return EXPANDED;
+                return VISIBLE_TYPE_EXPANDED;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 429889d..2a8b4ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -45,9 +45,6 @@
         public StatusBarNotification notification;
         public StatusBarIconView icon;
         public ExpandableNotificationRow row; // the outer expanded view
-        public View expanded; // the inflated RemoteViews
-        public View expandedPublic; // for insecure lockscreens
-        public View expandedBig;
         private boolean interruption;
         public boolean autoRedacted; // whether the redacted notification was generated by us
         public boolean legacy; // whether the notification has a legacy, dark background
@@ -58,14 +55,6 @@
             this.notification = n;
             this.icon = ic;
         }
-        public void setBigContentView(View bigContentView) {
-            this.expandedBig = bigContentView;
-            row.setExpandable(bigContentView != null);
-        }
-        public View getBigContentView() {
-            return expandedBig;
-        }
-        public View getPublicContentView() { return expandedPublic; }
 
         public void setInterruption() {
             interruption = true;
@@ -81,15 +70,28 @@
         public void reset() {
             // NOTE: Icon needs to be preserved for now.
             // We should fix this at some point.
-            expanded = null;
-            expandedPublic = null;
-            expandedBig = null;
             autoRedacted = false;
             legacy = false;
             if (row != null) {
                 row.reset();
             }
         }
+
+        public View getContentView() {
+            return row.getPrivateLayout().getContractedChild();
+        }
+
+        public View getExpandedContentView() {
+            return row.getPrivateLayout().getExpandedChild();
+        }
+
+        public View getHeadsUpContentView() {
+            return row.getPrivateLayout().getHeadsUpChild();
+        }
+
+        public View getPublicContentView() {
+            return row.getPublicLayout().getContractedChild();
+        }
     }
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
@@ -258,7 +260,7 @@
      */
     public boolean hasActiveClearableNotifications() {
         for (Entry e : mSortedAndFiltered) {
-            if (e.expanded != null) { // the view successfully inflated
+            if (e.getContentView() != null) { // the view successfully inflated
                 if (e.notification.isClearable()) {
                     return true;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 3997807..fe7bc97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -27,7 +27,7 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 /**
- * A Helper class to handle touches on the heads-up views
+ * A helper class to handle touches on the heads-up views.
  */
 public class HeadsUpTouchHelper implements Gefingerpoken {
 
@@ -37,19 +37,30 @@
     private float mTouchSlop;
     private float mInitialTouchX;
     private float mInitialTouchY;
-    private boolean mMotionOnHeadsUpView;
+    private boolean mTouchingHeadsUpView;
     private boolean mTrackingHeadsUp;
     private boolean mCollapseSnoozes;
     private NotificationPanelView mPanel;
     private ExpandableNotificationRow mPickedChild;
 
+    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
+            NotificationStackScrollLayout stackScroller,
+            NotificationPanelView notificationPanelView) {
+        mHeadsUpManager = headsUpManager;
+        mStackScroller = stackScroller;
+        mPanel = notificationPanelView;
+        Context context = stackScroller.getContext();
+        final ViewConfiguration configuration = ViewConfiguration.get(context);
+        mTouchSlop = configuration.getScaledTouchSlop();
+    }
+
     public boolean isTrackingHeadsUp() {
         return mTrackingHeadsUp;
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (!mMotionOnHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+        if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
             return false;
         }
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
@@ -65,10 +76,10 @@
                 mInitialTouchX = x;
                 setTrackingHeadsUp(false);
                 ExpandableView child = mStackScroller.getChildAtPosition(x, y);
-                mMotionOnHeadsUpView = false;
+                mTouchingHeadsUpView = false;
                 if (child instanceof ExpandableNotificationRow) {
                     mPickedChild = (ExpandableNotificationRow) child;
-                    mMotionOnHeadsUpView = mPickedChild.isHeadsUp() && !mPickedChild.isInShade();
+                    mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned();
                 }
                 break;
             case MotionEvent.ACTION_POINTER_UP:
@@ -97,7 +108,8 @@
 
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                if (mPickedChild != null && mMotionOnHeadsUpView) {
+                if (mPickedChild != null && mTouchingHeadsUpView) {
+                    // We may swallow this click if the heads up just came in.
                     if (mHeadsUpManager.shouldSwallowClick(
                             mPickedChild.getStatusBarNotification().getKey())) {
                         endMotion();
@@ -141,20 +153,6 @@
     private void endMotion() {
         mTrackingPointer = -1;
         mPickedChild = null;
-        mMotionOnHeadsUpView = false;
-    }
-
-    public ExpandableView getPickedChild() {
-        return mPickedChild;
-    }
-
-    public void bind(HeadsUpManager headsUpManager, NotificationStackScrollLayout stackScroller,
-            NotificationPanelView notificationPanelView) {
-        mHeadsUpManager = headsUpManager;
-        mStackScroller = stackScroller;
-        mPanel = notificationPanelView;
-        Context context = stackScroller.getContext();
-        final ViewConfiguration configuration = ViewConfiguration.get(context);
-        mTouchSlop = configuration.getScaledTouchSlop();
+        mTouchingHeadsUpView = false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index e5ef6ff..fabc1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -86,7 +86,7 @@
 
     private KeyguardAffordanceView mCameraImageView;
     private KeyguardAffordanceView mPhoneImageView;
-    private KeyguardAffordanceView mLockIcon;
+    private LockIcon mLockIcon;
     private TextView mIndicationText;
     private ViewGroup mPreviewContainer;
 
@@ -102,11 +102,8 @@
     private AccessibilityController mAccessibilityController;
     private PhoneStatusBar mPhoneStatusBar;
 
-    private final TrustDrawable mTrustDrawable;
     private final Interpolator mLinearOutSlowInInterpolator;
-    private int mLastUnlockIconRes = 0;
     private boolean mPrewarmSent;
-    private boolean mTransientFpError;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -123,7 +120,6 @@
     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mTrustDrawable = new TrustDrawable(mContext);
         mLinearOutSlowInInterpolator =
                 AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
     }
@@ -169,20 +165,19 @@
         mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
         mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
         mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
-        mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
+        mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
         mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
         watchForCameraPolicyChanges();
         updateCameraVisibility();
         updatePhoneVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
-        updateLockIcon();
+        mLockIcon.update();
         setClipChildren(false);
         setClipToPadding(false);
         mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
         inflatePreviews();
         mLockIcon.setOnClickListener(this);
-        mLockIcon.setBackground(mTrustDrawable);
         mLockIcon.setOnLongClickListener(this);
         mCameraImageView.setOnClickListener(this);
         mPhoneImageView.setOnClickListener(this);
@@ -222,6 +217,7 @@
 
     public void setAccessibilityController(AccessibilityController accessibilityController) {
         mAccessibilityController = accessibilityController;
+        mLockIcon.setAccessibilityController(accessibilityController);
         accessibilityController.addStateChangedCallback(this);
     }
 
@@ -233,9 +229,9 @@
     private Intent getCameraIntent() {
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         boolean currentUserHasTrust = updateMonitor.getUserHasTrust(
-                mLockPatternUtils.getCurrentUser());
-        return mLockPatternUtils.isSecure() && !currentUserHasTrust
-                ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+                KeyguardUpdateMonitor.getCurrentUser());
+        boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+        return (secure && !currentUserHasTrust) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
     }
 
     private void updateCameraVisibility() {
@@ -245,7 +241,7 @@
         }
         ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
                 PackageManager.MATCH_DEFAULT_ONLY,
-                mLockPatternUtils.getCurrentUser());
+                KeyguardUpdateMonitor.getCurrentUser());
         boolean visible = !isCameraDisabledByDpm() && resolved != null
                 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance);
         mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -294,21 +290,7 @@
         mPhoneImageView.setClickable(touchExplorationEnabled);
         mCameraImageView.setFocusable(accessibilityEnabled);
         mPhoneImageView.setFocusable(accessibilityEnabled);
-        updateLockIconClickability();
-    }
-
-    private void updateLockIconClickability() {
-        if (mAccessibilityController == null) {
-            return;
-        }
-        boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
-        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
-                && !mAccessibilityController.isAccessibilityEnabled();
-        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
-                && !clickToForceLock;
-        mLockIcon.setClickable(clickToForceLock || clickToUnlock);
-        mLockIcon.setLongClickable(longClickToForceLock);
-        mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
+        mLockIcon.update();
     }
 
     @Override
@@ -339,13 +321,13 @@
                 0 /* velocityDp - N/A */);
         mIndicationController.showTransientIndication(
                 R.string.keyguard_indication_trust_disabled);
-        mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser());
+        mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
     }
 
     public void prewarmCamera() {
         Intent intent = getCameraIntent();
         String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
-                mLockPatternUtils.getCurrentUser());
+                KeyguardUpdateMonitor.getCurrentUser());
         if (targetPackage != null) {
             Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM);
             prewarm.setPackage(targetPackage);
@@ -361,7 +343,7 @@
         mPrewarmSent = false;
         Intent intent = getCameraIntent();
         String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
-                mLockPatternUtils.getCurrentUser());
+                KeyguardUpdateMonitor.getCurrentUser());
         if (targetPackage != null) {
             Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN);
             prewarm.setPackage(targetPackage);
@@ -375,7 +357,7 @@
         mPrewarmSent = false;
         final Intent intent = getCameraIntent();
         boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
-                mContext, intent, mLockPatternUtils.getCurrentUser());
+                mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
         if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
             AsyncTask.execute(new Runnable() {
                 @Override
@@ -409,69 +391,12 @@
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
-        if (isShown()) {
-            mTrustDrawable.start();
-        } else {
-            mTrustDrawable.stop();
-        }
         if (changedView == this && visibility == VISIBLE) {
-            updateLockIcon();
+            mLockIcon.update();
             updateCameraVisibility();
         }
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mTrustDrawable.stop();
-    }
-
-    private void updateLockIcon() {
-        boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
-        if (visible) {
-            mTrustDrawable.start();
-        } else {
-            mTrustDrawable.stop();
-        }
-        if (!visible) {
-            return;
-        }
-        // TODO: Real icon for facelock.
-        boolean isFingerprintIcon =
-                KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
-        boolean anyFingerprintIcon = isFingerprintIcon || mTransientFpError;
-        int iconRes = mTransientFpError ? R.drawable.ic_fingerprint_error
-                : isFingerprintIcon ? R.drawable.ic_fingerprint
-                : mUnlockMethodCache.isFaceUnlockRunning()
-                        ? com.android.internal.R.drawable.ic_account_circle
-                : mUnlockMethodCache.isCurrentlyInsecure() ? R.drawable.ic_lock_open_24dp
-                : R.drawable.ic_lock_24dp;
-
-        if (mLastUnlockIconRes != iconRes) {
-            Drawable icon = mContext.getDrawable(iconRes);
-            int iconHeight = getResources().getDimensionPixelSize(
-                    R.dimen.keyguard_affordance_icon_height);
-            int iconWidth = getResources().getDimensionPixelSize(
-                    R.dimen.keyguard_affordance_icon_width);
-            if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
-                    || icon.getIntrinsicWidth() != iconWidth)) {
-                icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
-            }
-            mLockIcon.setImageDrawable(icon);
-            mLockIcon.setPaddingRelative(0, 0, 0, anyFingerprintIcon
-                    ? getResources().getDimensionPixelSize(
-                            R.dimen.fingerprint_icon_additional_padding)
-                    : 0);
-            mLockIcon.setRestingAlpha(
-                    anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
-        }
-
-        // Hide trust circle when fingerprint is running.
-        boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
-        mTrustDrawable.setTrustManaged(trustManaged);
-        updateLockIconClickability();
-    }
-
     public KeyguardAffordanceView getPhoneView() {
         return mPhoneImageView;
     }
@@ -503,7 +428,7 @@
 
     @Override
     public void onUnlockMethodStateChanged() {
-        updateLockIcon();
+        mLockIcon.update();
         updateCameraVisibility();
     }
 
@@ -563,9 +488,8 @@
     private final Runnable mTransientFpErrorClearRunnable = new Runnable() {
         @Override
         public void run() {
-            mTransientFpError = false;
+            mLockIcon.setTransientFpError(false);
             mIndicationController.hideTransientIndication();
-            updateLockIcon();
         }
     };
 
@@ -578,17 +502,17 @@
 
         @Override
         public void onScreenTurnedOn() {
-            updateLockIcon();
+            mLockIcon.update();
         }
 
         @Override
         public void onScreenTurnedOff(int why) {
-            updateLockIcon();
+            mLockIcon.update();
         }
 
         @Override
         public void onKeyguardVisibilityChanged(boolean showing) {
-            updateLockIcon();
+            mLockIcon.update();
         }
 
         @Override
@@ -597,24 +521,21 @@
 
         @Override
         public void onFingerprintRunningStateChanged(boolean running) {
-            updateLockIcon();
+            mLockIcon.update();
         }
 
         @Override
         public void onFingerprintHelp(int msgId, String helpString) {
-            mTransientFpError = true;
+            mLockIcon.setTransientFpError(true);
             mIndicationController.showTransientIndication(helpString,
                     getResources().getColor(R.color.system_warning_color, null));
             removeCallbacks(mTransientFpErrorClearRunnable);
             postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT);
-            updateLockIcon();
         }
 
         @Override
         public void onFingerprintError(int msgId, String errString) {
             // TODO: Go to bouncer if this is "too many attempts" (lockout) error.
-            Log.i(TAG, "FP Error: " + errString);
-            updateLockIcon();
         }
     };
 
@@ -622,29 +543,4 @@
             KeyguardIndicationController keyguardIndicationController) {
         mIndicationController = keyguardIndicationController;
     }
-
-    /**
-     * A wrapper around another Drawable that overrides the intrinsic size.
-     */
-    private static class IntrinsicSizeDrawable extends InsetDrawable {
-
-        private final int mIntrinsicWidth;
-        private final int mIntrinsicHeight;
-
-        public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
-            super(drawable, 0);
-            mIntrinsicWidth = intrinsicWidth;
-            mIntrinsicHeight = intrinsicHeight;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return mIntrinsicWidth;
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mIntrinsicHeight;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
new file mode 100644
index 0000000..66f3232
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.policy.AccessibilityController;
+
+/**
+ * Manages the different states and animations of the unlock icon.
+ */
+public class LockIcon extends KeyguardAffordanceView {
+
+
+    private static final int STATE_LOCKED = 0;
+    private static final int STATE_LOCK_OPEN = 1;
+    private static final int STATE_FACE_UNLOCK = 2;
+    private static final int STATE_FINGERPRINT = 3;
+    private static final int STATE_FINGERPRINT_ERROR = 4;
+
+    private int mLastState = 0;
+    private boolean mTransientFpError;
+    private final TrustDrawable mTrustDrawable;
+    private final UnlockMethodCache mUnlockMethodCache;
+    private AccessibilityController mAccessibilityController;
+
+    public LockIcon(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mTrustDrawable = new TrustDrawable(context);
+        setBackground(mTrustDrawable);
+        mUnlockMethodCache = UnlockMethodCache.getInstance(context);
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        if (isShown()) {
+            mTrustDrawable.start();
+        } else {
+            mTrustDrawable.stop();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mTrustDrawable.stop();
+    }
+
+    public void setTransientFpError(boolean transientFpError) {
+        mTransientFpError = transientFpError;
+        update();
+    }
+
+    public void update() {
+        boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
+        if (visible) {
+            mTrustDrawable.start();
+        } else {
+            mTrustDrawable.stop();
+        }
+        if (!visible) {
+            return;
+        }
+        // TODO: Real icon for facelock.
+        int state = getState();
+        boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+        if (state != mLastState) {
+            int iconRes = getAnimationResForTransition(mLastState, state);
+            if (iconRes == -1) {
+                iconRes = getIconForState(state);
+            }
+            Drawable icon = mContext.getDrawable(iconRes);
+            AnimatedVectorDrawable animation = null;
+            if (icon instanceof AnimatedVectorDrawable) {
+                animation = (AnimatedVectorDrawable) icon;
+            }
+            int iconHeight = getResources().getDimensionPixelSize(
+                    R.dimen.keyguard_affordance_icon_height);
+            int iconWidth = getResources().getDimensionPixelSize(
+                    R.dimen.keyguard_affordance_icon_width);
+            if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
+                    || icon.getIntrinsicWidth() != iconWidth)) {
+                icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
+            }
+            setPaddingRelative(0, 0, 0, anyFingerprintIcon
+                    ? getResources().getDimensionPixelSize(
+                    R.dimen.fingerprint_icon_additional_padding)
+                    : 0);
+            setRestingAlpha(
+                    anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
+            setImageDrawable(icon);
+            if (animation != null) {
+                animation.start();
+            }
+        }
+
+        // Hide trust circle when fingerprint is running.
+        boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
+        mTrustDrawable.setTrustManaged(trustManaged);
+        mLastState = state;
+        updateClickability();
+    }
+
+    private void updateClickability() {
+        if (mAccessibilityController == null) {
+            return;
+        }
+        boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
+        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+                && !mAccessibilityController.isAccessibilityEnabled();
+        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+                && !clickToForceLock;
+        setClickable(clickToForceLock || clickToUnlock);
+        setLongClickable(longClickToForceLock);
+        setFocusable(mAccessibilityController.isAccessibilityEnabled());
+    }
+
+    public void setAccessibilityController(AccessibilityController accessibilityController) {
+        mAccessibilityController = accessibilityController;
+    }
+
+    private int getIconForState(int state) {
+        switch (state) {
+            case STATE_LOCKED:
+                return R.drawable.ic_lock_24dp;
+            case STATE_LOCK_OPEN:
+                return R.drawable.ic_lock_open_24dp;
+            case STATE_FACE_UNLOCK:
+                return com.android.internal.R.drawable.ic_account_circle;
+            case STATE_FINGERPRINT:
+                return R.drawable.ic_fingerprint;
+            case STATE_FINGERPRINT_ERROR:
+                return R.drawable.ic_fingerprint_error;
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    private int getAnimationResForTransition(int oldState, int newState) {
+        if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+            return R.drawable.lockscreen_fingerprint_error_state_animation;
+        } else {
+            return -1;
+        }
+    }
+
+    private int getState() {
+        boolean fingerprintRunning =
+                KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
+        if (mTransientFpError) {
+            return STATE_FINGERPRINT_ERROR;
+        } else if (fingerprintRunning) {
+            return STATE_FINGERPRINT;
+        } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
+            return STATE_FACE_UNLOCK;
+        } else if (mUnlockMethodCache.isCurrentlyInsecure()) {
+            return STATE_LOCK_OPEN;
+        } else {
+            return STATE_LOCKED;
+        }
+    }
+
+    /**
+     * A wrapper around another Drawable that overrides the intrinsic size.
+     */
+    private static class IntrinsicSizeDrawable extends InsetDrawable {
+
+        private final int mIntrinsicWidth;
+        private final int mIntrinsicHeight;
+
+        public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
+            super(drawable, 0);
+            mIntrinsicWidth = intrinsicWidth;
+            mIntrinsicHeight = intrinsicHeight;
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return mIntrinsicWidth;
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return mIntrinsicHeight;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b87c25b..a8ecc42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -182,11 +182,11 @@
 
     private float mKeyguardStatusBarAnimateAlpha = 1f;
     private int mOldLayoutDirection;
-    private HeadsUpTouchHelper mHeadsUpTouchHelper = new HeadsUpTouchHelper();
-    private boolean mPinnedHeadsUpExist;
-    private boolean mExpansionIsFromHeadsUp;
-    private int mBottomBarHeight;
+    private HeadsUpTouchHelper mHeadsUpTouchHelper;
+    private boolean mIsExpansionFromHeadsUp;
+    private int mNavigationBarBottomHeight;
     private boolean mExpandingFromHeadsUp;
+    private boolean mCollapsedOnDown;
     private int mPositionMinSideMargin;
     private int mLastOrientation = -1;
 
@@ -327,7 +327,7 @@
         } else if (!mQsExpanded) {
             setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
         }
-        mNotificationStackScroller.setStackHeight(getExpandedHeight());
+        updateStackHeight(getExpandedHeight());
         updateHeader();
         mNotificationStackScroller.updateIsSmallScreen(
                 mHeader.getCollapsedHeight() + mQsPeekHeight);
@@ -534,17 +534,16 @@
     }
 
     @Override
-    public boolean
-    onInterceptTouchEvent(MotionEvent event) {
+    public boolean onInterceptTouchEvent(MotionEvent event) {
         if (mBlockTouches) {
             return false;
         }
         initDownStates(event);
         if (mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
-            mExpansionIsFromHeadsUp = true;
+            mIsExpansionFromHeadsUp = true;
             return true;
         }
-        if (!isShadeCollapsed() && onQsIntercept(event)) {
+        if (!isFullyCollapsed() && onQsIntercept(event)) {
             return true;
         }
         return super.onInterceptTouchEvent(event);
@@ -641,6 +640,7 @@
             mOnlyAffordanceInThisMotion = false;
             mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
             mDozingOnDown = isDozing();
+            mCollapsedOnDown = isFullyCollapsed();
         }
     }
 
@@ -695,7 +695,7 @@
             return true;
         }
         mHeadsUpTouchHelper.onTouchEvent(event);
-        if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQSTouch(event)) {
+        if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
             return true;
         }
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -705,7 +705,7 @@
         return true;
     }
 
-    private boolean handleQSTouch(MotionEvent event) {
+    private boolean handleQsTouch(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
                 && mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded
                 && mQsExpansionEnabled) {
@@ -718,7 +718,7 @@
             mInitialTouchY = event.getX();
             mInitialTouchX = event.getY();
         }
-        if (!isShadeCollapsed()) {
+        if (!isFullyCollapsed()) {
             handleQsDown(event);
         }
         if (!mQsExpandImmediate && mQsTracking) {
@@ -731,7 +731,7 @@
                 || event.getActionMasked() == MotionEvent.ACTION_UP) {
             mConflictingQsExpansionGesture = false;
         }
-        if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isShadeCollapsed()
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()
                 && mQsExpansionEnabled) {
             mTwoFingerQsExpandPossible = true;
         }
@@ -1191,8 +1191,8 @@
         updateEmptyShadeView();
         mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
                 && !mStackScrollerOverscrolling && mQsScrimEnabled
-                ? View.VISIBLE
-                : View.INVISIBLE);
+                        ? View.VISIBLE
+                        : View.INVISIBLE);
         if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
             mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
         }
@@ -1386,7 +1386,7 @@
      * @return Whether we should intercept a gesture to open Quick Settings.
      */
     private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
-        if (!mQsExpansionEnabled) {
+        if (!mQsExpansionEnabled || mCollapsedOnDown) {
             return false;
         }
         View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
@@ -1457,12 +1457,12 @@
             setQsExpansion(mQsMinExpansionHeight
                     + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
         }
-        mNotificationStackScroller.setStackHeight(expandedHeight);
+        updateStackHeight(expandedHeight);
         updateHeader();
         updateUnlockIcon();
         updateNotificationTranslucency();
-        mHeadsUpManager.setIsExpanded(!isShadeCollapsed());
-        mNotificationStackScroller.setShadeExpanded(!isShadeCollapsed());
+        mHeadsUpManager.setIsExpanded(!isFullyCollapsed());
+        mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
         if (DEBUG) {
             invalidate();
         }
@@ -1535,21 +1535,19 @@
         float alpha;
         if (mExpandingFromHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
             alpha = 1f;
-            if (mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
-                mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
-            }
         } else {
             alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight())
                     / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
                     - mNotificationStackScroller.getCollapseSecondCardPadding());
             alpha = Math.max(0, Math.min(alpha, 1));
             alpha = (float) Math.pow(alpha, 0.75);
-            if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
-                mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
-            } else if (alpha == 1f
-                    && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
-                mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
-            }
+        }
+
+        if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
+            mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
+        } else if (alpha == 1f
+                && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
+            mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
         }
         mNotificationStackScroller.setAlpha(alpha);
     }
@@ -1615,7 +1613,7 @@
         }
         float stackTranslation = mNotificationStackScroller.getStackTranslation();
         float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
-        if (mHeadsUpManager.hasPinnedHeadsUp() || mExpansionIsFromHeadsUp) {
+        if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
             translation = mNotificationStackScroller.getTopPadding() + stackTranslation
                     - mNotificationTopPadding - mQsMinExpansionHeight;
         }
@@ -1683,16 +1681,16 @@
         mHeadsUpManager.onExpandingFinished();
         mIsExpanding = false;
         mScrollYOverride = -1;
-        if (isShadeCollapsed()) {
+        if (isFullyCollapsed()) {
             setListening(false);
         } else {
             setListening(true);
         }
         mQsExpandImmediate = false;
         mTwoFingerQsExpandPossible = false;
-        mExpansionIsFromHeadsUp = false;
-        mNotificationStackScroller.setTrackingHeadsUp(mHeadsUpTouchHelper.isTrackingHeadsUp());
-        mExpandingFromHeadsUp = mHeadsUpTouchHelper.isTrackingHeadsUp();
+        mIsExpansionFromHeadsUp = false;
+        mNotificationStackScroller.setTrackingHeadsUp(false);
+        mExpandingFromHeadsUp = false;
     }
 
     private void setListening(boolean listening) {
@@ -1793,13 +1791,13 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        mBottomBarHeight = insets.getSystemWindowInsetBottom();
+        mNavigationBarBottomHeight = insets.getSystemWindowInsetBottom();
         updateMaxHeadsUpTranslation();
         return insets;
     }
 
     private void updateMaxHeadsUpTranslation() {
-        mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mBottomBarHeight);
+        mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight);
     }
 
     @Override
@@ -2160,48 +2158,43 @@
     }
 
     @Override
-    public void OnPinnedHeadsUpExistChanged(final boolean exist, boolean changeImmediatly) {
-        if (exist != mPinnedHeadsUpExist) {
-            mPinnedHeadsUpExist = exist;
-            if (exist) {
-                mHeadsUpExistenceChangedRunnable.run();
-                updateNotificationTranslucency();
-            } else {
-                mNotificationStackScroller.performOnAnimationFinished(
-                        mHeadsUpExistenceChangedRunnable);
-            }
+    public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
+        if (inPinnedMode) {
+            mHeadsUpExistenceChangedRunnable.run();
+            updateNotificationTranslucency();
+        } else {
+            mNotificationStackScroller.runAfterAnimationFinished(
+                    mHeadsUpExistenceChangedRunnable);
         }
     }
 
     @Override
-    public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
-        if (isHeadsUp) {
-            mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
-        }
+    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+        mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
     }
 
     @Override
-    public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    }
+
+    @Override
+    public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
         mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
     }
 
     @Override
-    protected boolean isShadeCollapsed() {
-        return mExpandedHeight == 0;
-    }
-
-    @Override
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
         super.setHeadsUpManager(headsUpManager);
-        mHeadsUpTouchHelper.bind(headsUpManager, mNotificationStackScroller, this);
+        mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
+                this);
     }
 
     public void setTrackingHeadsUp(boolean tracking) {
         if (tracking) {
-            // otherwise we update the state when the expansion is finished
             mNotificationStackScroller.setTrackingHeadsUp(true);
             mExpandingFromHeadsUp = true;
         }
+        // otherwise we update the state when the expansion is finished
     }
 
     @Override
@@ -2241,4 +2234,9 @@
         mScrollView.setTranslationX(translation);
         mHeader.setTranslationX(translation);
     }
+
+    private void updateStackHeight(float stackHeight) {
+        mNotificationStackScroller.setStackHeight(stackHeight);
+        updateKeyguardBottomAreaAlpha();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 4452dd7c..85f312c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -46,13 +46,13 @@
 public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
     public static final String TAG = PanelView.class.getSimpleName();
-    protected HeadsUpManager mHeadsUpManager;
-
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
     }
 
     protected PhoneStatusBar mStatusBar;
+    protected HeadsUpManager mHeadsUpManager;
+
     private float mPeekHeight;
     private float mHintDistance;
     private int mEdgeTapAreaWidth;
@@ -242,15 +242,15 @@
         final float y = event.getY(pointerIndex);
 
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mGestureWaitForTouchSlop = isShadeCollapsed() || hasConflictingGestures();
-            mIgnoreXTouchSlop = isShadeCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
+            mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures();
+            mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
         }
 
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                 mJustPeeked = false;
-                mPanelClosedOnDown = isShadeCollapsed();
+                mPanelClosedOnDown = isFullyCollapsed();
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mMotionAborted = false;
@@ -268,7 +268,7 @@
                             || mPeekPending || mPeekAnimator != null;
                     onTrackingStarted();
                 }
-                if (isShadeCollapsed()) {
+                if (isFullyCollapsed()) {
                     schedulePeek();
                 }
                 break;
@@ -472,7 +472,7 @@
                 mTouchSlopExceeded = false;
                 mJustPeeked = false;
                 mMotionAborted = false;
-                mPanelClosedOnDown = isShadeCollapsed();
+                mPanelClosedOnDown = isFullyCollapsed();
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mTouchAboveFalsingThreshold = false;
@@ -707,7 +707,7 @@
         // If the user isn't actively poking us, let's update the height
         if ((!mTracking || isTrackingBlocked())
                 && mHeightAnimator == null
-                && !isShadeCollapsed()
+                && !isFullyCollapsed()
                 && currentMaxPanelHeight != mExpandedHeight
                 && !mPeekPending
                 && mPeekAnimator == null
@@ -1057,8 +1057,6 @@
      */
     protected abstract int getClearAllHeight();
 
-    protected abstract boolean isShadeCollapsed();
-
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
     }
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 6b17589..9a6a80e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1152,11 +1152,11 @@
 
     @Override
     public void removeNotification(String key, RankingMap ranking) {
-        boolean defferRemoval = false;
+        boolean deferRemoval = false;
         if (mHeadsUpManager.isHeadsUp(key)) {
-            defferRemoval = !mHeadsUpManager.removeNotification(key);
+            deferRemoval = !mHeadsUpManager.removeNotification(key);
         }
-        if (defferRemoval) {
+        if (deferRemoval) {
             mLatestRankingMap = ranking;
             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
             return;
@@ -1293,13 +1293,20 @@
         updateClearAll();
         updateEmptyShadeView();
 
-        // Disable QS if device not provisioned.
-        // If the user switcher is simple then disable QS during setup because
-        // the user intends to use the lock screen user switcher, QS in not needed.
+        updateQsExpansionEnabled();
+        mShadeUpdates.check();
+    }
+
+    /**
+     * Disable QS if device not provisioned.
+     * If the user switcher is simple then disable QS during setup because
+     * the user intends to use the lock screen user switcher, QS in not needed.
+     */
+    private void updateQsExpansionEnabled() {
         mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
                 && (mUserSetup || mUserSwitcherController == null
-                        || !mUserSwitcherController.isSimpleUserSwitcher()));
-        mShadeUpdates.check();
+                        || !mUserSwitcherController.isSimpleUserSwitcher())
+                && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0));
     }
 
     private void updateNotificationShadeForChildren() {
@@ -1732,6 +1739,9 @@
         flagdbg.append(((diff1  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
         flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
         flagdbg.append(((diff1  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
+        flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
+                : "quick_settings");
+        flagdbg.append(((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
         flagdbg.append(">");
         Log.d(TAG, flagdbg.toString());
 
@@ -1780,6 +1790,10 @@
                     (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
             mHeadsUpObserver.onChange(true);
         }
+
+        if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
+            updateQsExpansionEnabled();
+        }
     }
 
     @Override
@@ -1838,8 +1852,8 @@
     }
 
     @Override
-    public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) {
-        if (exist) {
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+        if (inPinnedMode) {
             mStatusBarWindowManager.setHeadsUpShowing(true);
         } else {
             Runnable endRunnable = new Runnable() {
@@ -1850,20 +1864,25 @@
                     }
                 }
             };
-            if (changeImmediatly) {
+            if (!mNotificationPanel.isFullyCollapsed()) {
                 endRunnable.run();
             } else {
-                mStackScroller.performOnAnimationFinished(endRunnable);
+                mStackScroller.runAfterAnimationFinished(endRunnable);
             }
         }
     }
 
     @Override
-    public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
+    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+        dismissVolumeDialog();
     }
 
     @Override
-    public void OnHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    }
+
+    @Override
+    public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
         if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
             removeNotification(entry.key, mLatestRankingMap);
             mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
@@ -1880,10 +1899,11 @@
             boolean alertAgain) {
         final boolean wasHeadsUp = isHeadsUp(key);
         if (wasHeadsUp) {
-            mHeadsUpManager.updateNotification(entry, alertAgain);
             if (!shouldInterrupt) {
                 // We don't want this to be interrupting anymore, lets remove it
                 mHeadsUpManager.removeNotification(key);
+            } else {
+                mHeadsUpManager.updateNotification(entry, alertAgain);
             }
         } else if (shouldInterrupt && alertAgain) {
             // This notification was updated to be a heads-up, show it!
@@ -1929,7 +1949,7 @@
     }
 
     @Override
-    public void escalateHeadsUp() {
+    public void maybeEscalateHeadsUp() {
         TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
         for (HeadsUpManager.HeadsUpEntry entry : entries) {
             final StatusBarNotification sbn = entry.entry.notification;
@@ -2358,13 +2378,17 @@
         }
         // manually dismiss the volume panel when interacting with the nav bar
         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
-            if (mVolumeComponent != null) {
-                mVolumeComponent.dismissNow();
-            }
+            dismissVolumeDialog();
         }
         checkBarModes();
     }
 
+    private void dismissVolumeDialog() {
+        if (mVolumeComponent != null) {
+            mVolumeComponent.dismissNow();
+        }
+    }
+
     private void resumeSuspendedAutohide() {
         if (mAutohideSuspended) {
             scheduleAutohide();
@@ -2852,6 +2876,7 @@
         } catch (RemoteException e) {
             // Ignore.
         }
+        setNotificationsShown(newlyVisibleAr);
     }
 
     // State logging
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 fb42ba1d..0e8e844 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -224,14 +224,14 @@
         } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_zen_none;
-            zenDescription = mContext.getString(R.string.zen_no_interruptions);
+            zenDescription = mContext.getString(R.string.interruption_level_none);
         } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_zen_important;
-            zenDescription = mContext.getString(R.string.zen_important_interruptions);
+            zenDescription = mContext.getString(R.string.interruption_level_priority);
         }
 
-        if (DndTile.isVisible(mContext)
+        if (DndTile.isVisible(mContext) && !DndTile.isCombinedIcon(mContext)
                 && audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_silent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e701783..e6edbeac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -80,7 +80,7 @@
     private float mCurrentInFrontAlpha;
     private float mCurrentBehindAlpha;
     private float mCurrentHeadsUpAlpha = 1;
-    private int mAmountOfPinnedHeadsUps;
+    private int mPinnedHeadsUpCount;
     private float mTopHeadsUpDragAmount;
     private View mDraggedHeadsUpView;
 
@@ -347,25 +347,27 @@
     }
 
     @Override
-    public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) {
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
     }
 
     @Override
-    public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
-        if (isHeadsUp) {
-            mAmountOfPinnedHeadsUps++;
-        } else {
-            mAmountOfPinnedHeadsUps--;
-            if (headsUp == mDraggedHeadsUpView) {
-                mDraggedHeadsUpView = null;
-                mTopHeadsUpDragAmount = 0.0f;
-            }
+    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+        mPinnedHeadsUpCount++;
+        updateHeadsUpScrim(true);
+    }
+
+    @Override
+    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+        mPinnedHeadsUpCount--;
+        if (headsUp == mDraggedHeadsUpView) {
+            mDraggedHeadsUpView = null;
+            mTopHeadsUpDragAmount = 0.0f;
         }
         updateHeadsUpScrim(true);
     }
 
     @Override
-    public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
     }
 
     private void updateHeadsUpScrim(boolean animate) {
@@ -374,12 +376,10 @@
                 TAG_KEY_ANIM);
         float animEndValue = -1;
         if (previousAnimator != null) {
-            if ((animate || alpha == mCurrentHeadsUpAlpha)) {
-                // lets cancel any running animators
+            if (animate || alpha == mCurrentHeadsUpAlpha) {
                 previousAnimator.cancel();
             }
-            animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
-                    TAG_HUN_START_ALPHA);
+            animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_START_ALPHA);
         }
         if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) {
             if (animate) {
@@ -390,7 +390,7 @@
                 if (previousAnimator != null) {
                     float previousStartValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
                             TAG_HUN_START_ALPHA);
-                   float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
+                    float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
                            TAG_HUN_END_ALPHA);
                     // we need to increase all animation keyframes of the previous animator by the
                     // relative change to the end value
@@ -410,6 +410,13 @@
         }
     }
 
+    /**
+     * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
+     * the heads up is in its resting space and 1 means it's fully dragged out.
+     *
+     * @param draggedHeadsUpView the dragged view
+     * @param topHeadsUpDragAmount how far is it dragged
+     */
     public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
         mTopHeadsUpDragAmount = topHeadsUpDragAmount;
         mDraggedHeadsUpView = draggedHeadsUpView;
@@ -417,9 +424,9 @@
     }
 
     private float calculateHeadsUpAlpha() {
-        if (mAmountOfPinnedHeadsUps >= 2) {
+        if (mPinnedHeadsUpCount >= 2) {
             return 1.0f;
-        } else if (mAmountOfPinnedHeadsUps == 0) {
+        } else if (mPinnedHeadsUpCount == 0) {
             return 0.0f;
         } else {
             return 1.0f - mTopHeadsUpDragAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
index 4a43c47..45c8938 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 
 import java.util.HashMap;
 import java.util.List;
@@ -228,7 +229,7 @@
 
         // Get the list of applications that can handle the intent.
         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+                intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser());
         if (appList.size() == 0) {
             if (DEBUG) Log.d(TAG, "No targets found for secure camera intent");
             return false;
@@ -237,7 +238,7 @@
         // Get the application that the intent resolves to.
         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
                 PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                mLockPatternUtils.getCurrentUser());
+                KeyguardUpdateMonitor.getCurrentUser());
 
         if (resolved == null || resolved.activityInfo == null) {
             return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 65cd268..66d71f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -80,8 +80,8 @@
     }
 
     private void update(boolean updateAlways) {
-        int user = mLockPatternUtils.getCurrentUser();
-        boolean secure = mLockPatternUtils.isSecure();
+        int user = KeyguardUpdateMonitor.getCurrentUser();
+        boolean secure = mLockPatternUtils.isSecure(user);
         boolean currentlyInsecure = !secure ||  mKeyguardUpdateMonitor.getUserHasTrust(user);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index b4e4773..0db9221 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,11 +35,16 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Stack;
 import java.util.TreeSet;
 
+/**
+ * A manager which handles heads up notifications which is a special mode where
+ * they simply peek from the top of the screen.
+ */
 public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener {
     private static final String TAG = "HeadsUpManager";
     private static final boolean DEBUG = false;
@@ -48,7 +53,7 @@
     private final int mHeadsUpNotificationDecay;
     private final int mMinimumDisplayTime;
 
-    private final int mTouchSensitivityDelay;
+    private final int mTouchAcceptanceDelay;
     private final ArrayMap<String, Long> mSnoozedPackages;
     private final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>();
     private final int mDefaultSnoozeLengthMs;
@@ -67,13 +72,12 @@
 
         @Override
         public boolean release(HeadsUpEntry instance) {
-            instance.removeAutoCancelCallbacks();
+            instance.reset();
             mPoolObjects.push(instance);
             return true;
         }
     };
 
-
     private PhoneStatusBar mBar;
     private int mSnoozeLengthMs;
     private ContentObserver mSettingsObserver;
@@ -86,13 +90,12 @@
     private boolean mTrackingHeadsUp;
     private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
     private boolean mIsExpanded;
-    private boolean mHasPinnedHeadsUp;
+    private boolean mHasPinnedNotification;
     private int[] mTmpTwoArray = new int[2];
 
     public HeadsUpManager(final Context context, ViewTreeObserver observer) {
         Resources resources = context.getResources();
-        mTouchSensitivityDelay = resources.getInteger(R.integer.heads_up_sensitivity_delay);
-        if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
+        mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
         mSnoozedPackages = new ArrayMap<>();
         mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
         mSnoozeLengthMs = mDefaultSnoozeLengthMs;
@@ -116,7 +119,6 @@
         context.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
                 mSettingsObserver);
-        if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs);
         observer.addOnComputeInternalInsetsListener(this);
     }
 
@@ -154,7 +156,7 @@
         if (alert) {
             HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key);
             headsUpEntry.updateEntry();
-            setEntryToShade(headsUpEntry, mIsExpanded, false /* justAdded */, false);
+            setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */);
         }
     }
 
@@ -165,22 +167,23 @@
         headsUpEntry.setEntry(entry);
         mHeadsUpEntries.put(entry.key, headsUpEntry);
         entry.row.setHeadsUp(true);
-        setEntryToShade(headsUpEntry, mIsExpanded /* inShade */, true /* justAdded */, false);
+        setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */);
         for (OnHeadsUpChangedListener listener : mListeners) {
-            listener.OnHeadsUpStateChanged(entry, true);
+            listener.onHeadsUpStateChanged(entry, true);
         }
         entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
-    private void setEntryToShade(HeadsUpEntry headsUpEntry, boolean inShade, boolean justAdded,
-            boolean forceImmediate) {
+    private void setEntryPinned(HeadsUpEntry headsUpEntry, boolean isPinned) {
         ExpandableNotificationRow row = headsUpEntry.entry.row;
-        if (row.isInShade() != inShade || justAdded) {
-            row.setInShade(inShade);
-            if (!justAdded || !inShade) {
-                updatePinnedHeadsUpState(forceImmediate);
-                for (OnHeadsUpChangedListener listener : mListeners) {
-                    listener.OnHeadsUpPinnedChanged(row, !inShade);
+        if (row.isPinned() != isPinned) {
+            row.setPinned(isPinned);
+            updatePinnedMode();
+            for (OnHeadsUpChangedListener listener : mListeners) {
+                if (isPinned) {
+                    listener.onHeadsUpPinned(row);
+                } else {
+                    listener.onHeadsUpUnPinned(row);
                 }
             }
         }
@@ -189,24 +192,23 @@
     private void removeHeadsUpEntry(NotificationData.Entry entry) {
         HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
         mSortedEntries.remove(remove);
-        mEntryPool.release(remove);
         entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         entry.row.setHeadsUp(false);
-        setEntryToShade(remove, true /* inShade */, false /* justAdded */,
-                false /* forceImmediate */);
+        setEntryPinned(remove, false /* isPinned */);
         for (OnHeadsUpChangedListener listener : mListeners) {
-            listener.OnHeadsUpStateChanged(entry, false);
+            listener.onHeadsUpStateChanged(entry, false);
         }
+        mEntryPool.release(remove);
     }
 
-    private void updatePinnedHeadsUpState(boolean forceImmediate) {
-        boolean hasPinnedHeadsUp = hasPinnedHeadsUpInternal();
-        if (hasPinnedHeadsUp == mHasPinnedHeadsUp) {
+    private void updatePinnedMode() {
+        boolean hasPinnedNotification = hasPinnedNotificationInternal();
+        if (hasPinnedNotification == mHasPinnedNotification) {
             return;
         }
-        mHasPinnedHeadsUp = hasPinnedHeadsUp;
-        for (OnHeadsUpChangedListener listener :mListeners) {
-            listener.OnPinnedHeadsUpExistChanged(hasPinnedHeadsUp, forceImmediate);
+        mHasPinnedNotification = hasPinnedNotification;
+        for (OnHeadsUpChangedListener listener : mListeners) {
+            listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
         }
     }
 
@@ -222,7 +224,7 @@
             releaseImmediately(key);
             return true;
         } else {
-            getHeadsUpEntry(key).hideAsSoonAsPossible();
+            getHeadsUpEntry(key).removeAsSoonAsPossible();
             return false;
         }
     }
@@ -245,14 +247,13 @@
         return mHeadsUpEntries.containsKey(key);
     }
 
-
     /**
      * Push any current Heads Up notification down into the shade.
      */
     public void releaseAllImmediately() {
         if (DEBUG) Log.v(TAG, "releaseAllImmediately");
-        HashSet<String> keys = new HashSet<>(mHeadsUpEntries.keySet());
-        for (String key: keys) {
+        ArrayList<String> keys = new ArrayList<>(mHeadsUpEntries.keySet());
+        for (String key : keys) {
             releaseImmediately(key);
         }
     }
@@ -280,7 +281,7 @@
     }
 
     public void snooze() {
-        for (String key: mHeadsUpEntries.keySet()) {
+        for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
             String packageName = entry.entry.notification.getPackageName();
             mSnoozedPackages.put(snoozeKey(packageName, mUser),
@@ -310,8 +311,11 @@
     }
 
     /**
+     * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
+     * that a user might have consciously clicked on it.
+     *
      * @param key the key of the touched notification
-     * @return whether the touch is valid and should not be discarded
+     * @return whether the touch is invalid and should be discarded
      */
     public boolean shouldSwallowClick(String key) {
         HeadsUpEntry entry = mHeadsUpEntries.get(key);
@@ -322,14 +326,14 @@
     }
 
     public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        if (!mIsExpanded && mHasPinnedHeadsUp) {
+        if (!mIsExpanded && mHasPinnedNotification) {
             int minX = Integer.MAX_VALUE;
             int maxX = 0;
             int minY = Integer.MAX_VALUE;
             int maxY = 0;
-            for (HeadsUpEntry entry: mSortedEntries) {
+            for (HeadsUpEntry entry : mSortedEntries) {
                 ExpandableNotificationRow row = entry.entry.row;
-                if (!row.isInShade()) {
+                if (row.isPinned()) {
                     row.getLocationOnScreen(mTmpTwoArray);
                     minX = Math.min(minX, mTmpTwoArray[0]);
                     minY = Math.min(minY, 0);
@@ -349,7 +353,7 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("HeadsUpManager state:");
-        pw.print("  mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay);
+        pw.print("  mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay);
         pw.print("  mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
         pw.print("  now="); pw.println(SystemClock.elapsedRealtime());
         pw.print("  mUser="); pw.println(mUser);
@@ -365,38 +369,32 @@
     }
 
     public boolean hasPinnedHeadsUp() {
-        return mHasPinnedHeadsUp;
+        return mHasPinnedNotification;
     }
 
-    private boolean hasPinnedHeadsUpInternal() {
-        for (String key: mHeadsUpEntries.keySet()) {
+    private boolean hasPinnedNotificationInternal() {
+        for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
-            if (!entry.entry.row.isInShade()) {
+            if (entry.entry.row.isPinned()) {
                 return true;
             }
         }
         return false;
     }
 
-    public void addSwipedOutKey(String key) {
+    /**
+     * Notifies that a notification was swiped out and will be removed.
+     *
+     * @param key the notification key
+     */
+    public void addSwipedOutNotification(String key) {
         mSwipedOutKeys.add(key);
     }
 
-    public float getHighestPinnedHeadsUp() {
-        float max = 0;
-        for (HeadsUpEntry entry: mSortedEntries) {
-            if (!entry.entry.row.isInShade()) {
-                max = Math.max(max, entry.entry.row.getActualHeight());
-            }
-        }
-        return max;
-    }
-
-    public void releaseAllToShade() {
-        for (String key: mHeadsUpEntries.keySet()) {
+    public void unpinAll() {
+        for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
-            setEntryToShade(entry, true /* toShade */, false /* justAdded */,
-                    true /* forceImmediate */);
+            setEntryPinned(entry, false /* isPinned */);
         }
     }
 
@@ -420,7 +418,7 @@
         if (isExpanded != mIsExpanded) {
             mIsExpanded = isExpanded;
             if (isExpanded) {
-                releaseAllToShade();
+                unpinAll();
             }
         }
     }
@@ -430,6 +428,12 @@
         return topEntry != null ? topEntry.entry.row.getHeadsUpHeight() : 0;
     }
 
+    /**
+     * Compare two entries and decide how they should be ranked.
+     *
+     * @return -1 if the first argument should be ranked higher than the second, 1 if the second
+     * one should be ranked higher and 0 if they are equal.
+     */
     public int compare(NotificationData.Entry a, NotificationData.Entry b) {
         HeadsUpEntry aEntry = getHeadsUpEntry(a.key);
         HeadsUpEntry bEntry = getHeadsUpEntry(b.key);
@@ -439,6 +443,11 @@
         return aEntry.compareTo(bEntry);
     }
 
+
+    /**
+     * This represents a notification and how long it is in a heads up mode. It also manages its
+     * lifecycle automatically when created.
+     */
     public class HeadsUpEntry implements Comparable<HeadsUpEntry> {
         public NotificationData.Entry entry;
         public long postTime;
@@ -449,7 +458,7 @@
             this.entry = entry;
 
             // The actual post time will be just after the heads-up really slided in
-            postTime = mClock.currentTimeMillis() + mTouchSensitivityDelay;
+            postTime = mClock.currentTimeMillis() + mTouchAcceptanceDelay;
             mRemoveHeadsUpRunnable = new Runnable() {
                 @Override
                 public void run() {
@@ -467,7 +476,7 @@
             long currentTime = mClock.currentTimeMillis();
             earliestRemovaltime = currentTime + mMinimumDisplayTime;
             postTime = Math.max(postTime, currentTime);
-            removeAutoCancelCallbacks();
+            removeAutoRemovalCallbacks();
             if (canEntryDecay()) {
                 long finishTime = postTime + mHeadsUpNotificationDecay;
                 long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
@@ -487,7 +496,7 @@
                             : -1;
         }
 
-        public void removeAutoCancelCallbacks() {
+        public void removeAutoRemovalCallbacks() {
             mHandler.removeCallbacks(mRemoveHeadsUpRunnable);
         }
 
@@ -495,11 +504,17 @@
             return earliestRemovaltime < mClock.currentTimeMillis();
         }
 
-        public void hideAsSoonAsPossible() {
-            removeAutoCancelCallbacks();
+        public void removeAsSoonAsPossible() {
+            removeAutoRemovalCallbacks();
             mHandler.postDelayed(mRemoveHeadsUpRunnable,
                     earliestRemovaltime - mClock.currentTimeMillis());
         }
+
+        public void reset() {
+            removeAutoRemovalCallbacks();
+            entry = null;
+            mRemoveHeadsUpRunnable = null;
+        }
     }
 
     /**
@@ -519,8 +534,29 @@
     }
 
     public interface OnHeadsUpChangedListener {
-        void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly);
-        void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp);
-        void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp);
+        /**
+         * The state whether there exist pinned heads-ups or not changed.
+         *
+         * @param inPinnedMode whether there are any pinned heads-ups
+         */
+        void onHeadsUpPinnedModeChanged(boolean inPinnedMode);
+
+        /**
+         * A notification was just pinned to the top.
+         */
+        void onHeadsUpPinned(ExpandableNotificationRow headsUp);
+
+        /**
+         * A notification was just unpinned from the top.
+         */
+        void onHeadsUpUnPinned(ExpandableNotificationRow headsUp);
+
+        /**
+         * A notification just became a heads up or turned back to its normal state.
+         *
+         * @param entry the entry of the changed notification
+         * @param isHeadsUp whether the notification is now a headsUp notification
+         */
+        void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 0dce82f..5d89e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -26,6 +26,7 @@
 import android.view.View;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.statusbar.phone.KeyguardPreviewContainer;
 
 import java.util.List;
@@ -80,13 +81,13 @@
         WidgetInfo info = new WidgetInfo();
         PackageManager packageManager = mContext.getPackageManager();
         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+                intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser());
         if (appList.size() == 0) {
             return null;
         }
         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
                 PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                mLockPatternUtils.getCurrentUser());
+                KeyguardUpdateMonitor.getCurrentUser());
         if (wouldLaunchResolverActivity(resolved, appList)) {
             return null;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 67cc788..9d84a85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -35,6 +35,7 @@
     boolean isZenAvailable();
     ComponentName getEffectsSuppressor();
     boolean isCountdownConditionSupported();
+    int getCurrentUser();
 
     public static class Callback {
         public void onZenChanged(int zen) {}
@@ -45,4 +46,5 @@
         public void onManualRuleChanged(ZenRule rule) {}
         public void onConfigChanged(ZenModeConfig config) {}
     }
+
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 830a197..5b80ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
@@ -159,6 +160,11 @@
                 .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
     }
 
+    @Override
+    public int getCurrentUser() {
+        return ActivityManager.getCurrentUser();
+    }
+
     private void fireNextAlarmChanged() {
         for (Callback cb : mCallbacks) {
             cb.onNextAlarmChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java
new file mode 100644
index 0000000..05c0099
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.graphics.Path;
+import android.view.animation.PathInterpolator;
+
+/**
+ * An interpolator specifically designed for the appear animation of heads up notifications.
+ */
+public class HeadsUpAppearInterpolator extends PathInterpolator {
+    public HeadsUpAppearInterpolator() {
+        super(getAppearPath());
+    }
+
+    private static Path getAppearPath() {
+        Path path = new Path();
+        path.moveTo(0, 0);
+        float x1 = 250f;
+        float x2 = 150f;
+        float x3 = 100f;
+        float y1 = 90f;
+        float y2 = 78f;
+        float y3 = 80f;
+        float xTot = (x1 + x2 + x3);
+        path.cubicTo(x1 * 0.9f / xTot, 0f,
+                x1 * 0.8f / xTot, y1 / y3,
+                x1 / xTot , y1 / y3);
+        path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3,
+                (x1 + x2 * 0.2f) / xTot, y2 / y3,
+                (x1 + x2) / xTot, y2 / y3);
+        path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3,
+                (x1 + x2 + x3 * 0.2f) / xTot, 1f,
+                1f, 1f);
+        return path;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 88fc602..a1b0cae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -204,7 +204,6 @@
     private ViewGroup mScrollView;
     private boolean mInterceptDelegateEnabled;
     private boolean mDelegateToScrollView;
-
     private boolean mDisallowScrollingInThisMotion;
     private long mGoToFullShadeDelay;
     private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -487,9 +486,9 @@
         int stackHeight;
         float paddingOffset;
         boolean trackingHeadsUp = mTrackingHeadsUp;
-        int normalExpandPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
+        int normalUnfoldPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
                 : minStackHeight;
-        if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalExpandPositionStart
+        if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart
                 || getNotGoneChildCount() == 0) {
             paddingOffset = mTopPaddingOverflow;
             stackHeight = newStackHeight;
@@ -582,7 +581,7 @@
         if (v instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) v;
             if (row.isHeadsUp()) {
-                mHeadsUpManager.addSwipedOutKey(row.getStatusBarNotification().getKey());
+                mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
             }
         }
         final View veto = v.findViewById(R.id.veto);
@@ -626,10 +625,10 @@
         requestChildrenUpdate();
     }
 
-    public boolean isPinnedHeadsUp(View v) {
+    public static boolean isPinnedHeadsUp(View v) {
         if (v instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) v;
-            return row.isHeadsUp() && !row.isInShade();
+            return row.isHeadsUp() && row.isPinned();
         }
         return false;
     }
@@ -711,7 +710,7 @@
             if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
                 if (slidingChild instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
-                    if (row.isHeadsUp() && !row.isInShade()
+                    if (row.isHeadsUp() && row.isPinned()
                             && mHeadsUpManager.getTopEntry().entry.row != row) {
                         continue;
                     }
@@ -812,7 +811,8 @@
         }
         handleEmptySpaceClick(ev);
         boolean expandWantsIt = false;
-        if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
+        if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion
+                && isScrollingEnabled()) {
             if (isCancelOrUp) {
                 mExpandHelper.onlyObserveMovements(false);
             }
@@ -824,7 +824,8 @@
             }
         }
         boolean scrollerWantsIt = false;
-        if (!mSwipingInProgress && !mExpandingNotification && !mDisallowScrollingInThisMotion) {
+        if (mIsExpanded && !mSwipingInProgress && !mExpandingNotification
+                && !mDisallowScrollingInThisMotion) {
             scrollerWantsIt = onScrollTouch(ev);
         }
         boolean horizontalSwipeWantsIt = false;
@@ -1872,15 +1873,15 @@
             boolean onBottom = false;
             if (!mIsExpanded && !isHeadsUp) {
                 type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
-            } else if (mAddedHeadsUpChildren.contains(row) || (!row.isInShade() && !mIsExpanded)) {
-                if (!row.isInShade() || shouldHunAppearFromBottom(row)) {
+            } else if (mAddedHeadsUpChildren.contains(row) || (row.isPinned() && !mIsExpanded)) {
+                if (row.isPinned() || shouldHunAppearFromBottom(row)) {
                     // Our custom add animation
                     type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
                 } else {
                     // Normal add animation
                     type = AnimationEvent.ANIMATION_TYPE_ADD;
                 }
-                onBottom = row.isInShade();
+                onBottom = !row.isPinned();
             }
             AnimationEvent event = new AnimationEvent(row, type);
             event.headsUpFromBottom = onBottom;
@@ -2670,7 +2671,7 @@
         }
     }
 
-    public void performOnAnimationFinished(Runnable runnable) {
+    public void runAfterAnimationFinished(Runnable runnable) {
         mAnimationFinishedRunnables.add(runnable);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 2a49a4c..202063a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -311,7 +311,8 @@
                     StackViewState viewState = resultState.getViewStateForView(
                             nextChild);
                     // The child below the dragged one must be fully visible
-                    if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) {
+                    if (!NotificationStackScrollLayout.isPinnedHeadsUp(draggedView)
+                            || NotificationStackScrollLayout.isPinnedHeadsUp(nextChild)) {
                         viewState.alpha = 1;
                     }
                 }
@@ -324,14 +325,6 @@
         }
     }
 
-    private boolean isPinnedHeadsUpView(View view) {
-        if (view instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            return row.isHeadsUp() && !row.isInShade();
-        }
-        return false;
-    }
-
     /**
      * Update the visible children on the state.
      */
@@ -380,7 +373,7 @@
     /**
      * Determine the positions for the views. This is the main part of the algorithm.
      *
-     *  @param resultState The result state to update if a change to the properties of a child occurs
+     * @param resultState The result state to update if a change to the properties of a child occurs
      * @param algorithmState The state in which the current pass of the algorithm is currently in
      * @param ambientState The current ambient state
      */
@@ -515,11 +508,12 @@
             }
             StackViewState childState = resultState.getViewStateForView(row);
             boolean isTopEntry = topHeadsUpEntry == row;
-            if (!row.isInShade()) {
+            if (row.isPinned()) {
                 childState.yTranslation = 0;
                 childState.height = row.getHeadsUpHeight();
                 if (!isTopEntry) {
-                    // Ensure that a headsUp is never below the topmost headsUp
+                    // Ensure that a headsUp doesn't vertically extend further than the heads-up at
+                    // the top most z-position
                     StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
                     childState.height = row.getHeadsUpHeight();
                     childState.yTranslation = topState.yTranslation + topState.height
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index f5d94c8..b9466d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -21,11 +21,9 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
-import android.graphics.Path;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -78,6 +76,7 @@
     private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mHeadsUpAppearInterpolator;
     private final int mGoToFullShadeAppearingTranslation;
+    private final StackViewState mTmpState = new StackViewState();
     public NotificationStackScrollLayout mHostLayout;
     private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
             new ArrayList<>();
@@ -95,7 +94,6 @@
     private ValueAnimator mTopOverScrollAnimator;
     private ValueAnimator mBottomOverScrollAnimator;
     private ExpandableNotificationRow mChildExpandingView;
-    private StackViewState mTmpState = new StackViewState();
     private int mHeadsUpAppearHeightBottom;
     private boolean mShadeExpanded;
 
@@ -106,25 +104,7 @@
         mGoToFullShadeAppearingTranslation =
                 hostLayout.getContext().getResources().getDimensionPixelSize(
                         R.dimen.go_to_full_shade_appearing_translation);
-        Path path = new Path();
-        path.moveTo(0, 0);
-        float x1 = 250f;
-        float x2 = 150f;
-        float x3 = 100f;
-        float y1 = 90f;
-        float y2 = 78f;
-        float y3 = 80f;
-        float xTot = (x1 + x2 + x3);
-        path.cubicTo(x1 * 0.9f / xTot, 0f,
-                x1 * 0.8f / xTot, y1 / y3,
-                x1 / xTot , y1 / y3);
-        path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3,
-                (x1 + x2 * 0.2f) / xTot, y2 / y3,
-                (x1 + x2) / xTot, y2 / y3);
-        path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3,
-                (x1 + x2 + x3 * 0.2f) / xTot, 1f,
-                1f, 1f);
-        mHeadsUpAppearInterpolator = new PathInterpolator(path);
+        mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator();
     }
 
     public boolean isRunning() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index dda40d3..a5684a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -121,7 +121,7 @@
     }
 
     @Override
-    public void escalateHeadsUp() {
+    public void maybeEscalateHeadsUp() {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 240c210..e6c95b5 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -24,12 +24,20 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.MoveCallback;
+import android.os.Bundle;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.R;
 import com.android.systemui.SystemUI;
@@ -39,39 +47,93 @@
 public class StorageNotification extends SystemUI {
     private static final String TAG = "StorageNotification";
 
-    private static final int NOTIF_ID = 0x53544f52; // STOR
+    private static final int PUBLIC_ID = 0x53505542; // SPUB
+    private static final int PRIVATE_ID = 0x53505256; // SPRV
+    private static final int DISK_ID = 0x5344534b; // SDSK
+    private static final int MOVE_ID = 0x534d4f56; // SMOV
 
     private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
 
     // TODO: delay some notifications to avoid bumpy fast operations
-    // TODO: annoy user when private media is missing
 
     private NotificationManager mNotificationManager;
     private StorageManager mStorageManager;
 
+    private static class MoveInfo {
+        public int moveId;
+        public Bundle extras;
+        public String packageName;
+        public String label;
+        public String volumeUuid;
+    }
+
+    private final SparseArray<MoveInfo> mMoves = new SparseArray<>();
+
     private final StorageEventListener mListener = new StorageEventListener() {
         @Override
         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
-            onVolumeStateChangedInternal(vol, oldState, newState);
+            onVolumeStateChangedInternal(vol);
         }
 
         @Override
-        public void onVolumeMetadataChanged(VolumeInfo vol) {
+        public void onVolumeRecordChanged(VolumeRecord rec) {
             // Avoid kicking notifications when getting early metadata before
             // mounted. If already mounted, we're being kicked because of a
             // nickname or init'ed change.
-            if (vol.isMountedReadable()) {
-                onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
+            final VolumeInfo vol = mStorageManager.findVolumeByUuid(rec.getFsUuid());
+            if (vol != null && vol.isMountedReadable()) {
+                onVolumeStateChangedInternal(vol);
             }
         }
+
+        @Override
+        public void onVolumeForgotten(String fsUuid) {
+            // Stop annoying the user
+            mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+        }
+
+        @Override
+        public void onDiskScanned(DiskInfo disk, int volumeCount) {
+            onDiskScannedInternal(disk, volumeCount);
+        }
     };
 
     private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // TODO: kick this onto background thread
-            final String volId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID);
-            mStorageManager.setVolumeSnoozed(volId, true);
+            final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
+            mStorageManager.setVolumeSnoozed(fsUuid, true);
+        }
+    };
+
+    private final MoveCallback mMoveCallback = new MoveCallback() {
+        @Override
+        public void onCreated(int moveId, Bundle extras) {
+            final MoveInfo move = new MoveInfo();
+            move.moveId = moveId;
+            move.extras = extras;
+            if (extras != null) {
+                move.packageName = extras.getString(Intent.EXTRA_PACKAGE_NAME);
+                move.label = extras.getString(Intent.EXTRA_TITLE);
+                move.volumeUuid = extras.getString(VolumeRecord.EXTRA_FS_UUID);
+            }
+            mMoves.put(moveId, move);
+        }
+
+        @Override
+        public void onStatusChanged(int moveId, int status, long estMillis) {
+            final MoveInfo move = mMoves.get(moveId);
+            if (move == null) {
+                Log.w(TAG, "Ignoring unknown move " + moveId);
+                return;
+            }
+
+            if (PackageManager.isMoveStatusFinished(status)) {
+                onMoveFinished(move, status);
+            } else {
+                onMoveProgress(move, status, estMillis);
+            }
         }
     };
 
@@ -88,20 +150,99 @@
         // Kick current state into place
         final List<VolumeInfo> vols = mStorageManager.getVolumes();
         for (VolumeInfo vol : vols) {
-            onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
+            onVolumeStateChangedInternal(vol);
+        }
+
+        mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
+
+        updateMissingPrivateVolumes();
+    }
+
+    private void updateMissingPrivateVolumes() {
+        final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
+        for (VolumeRecord rec : recs) {
+            if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
+
+            final String fsUuid = rec.getFsUuid();
+            final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
+            if (info != null && info.isMountedWritable()) {
+                // Yay, private volume is here!
+                mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+
+            } else {
+                // Boo, annoy the user to reinsert the private volume
+                final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
+                        rec.getNickname());
+                final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
+
+                final Notification notif = new Notification.Builder(mContext)
+                        .setSmallIcon(R.drawable.stat_notify_sdcard)
+                        .setColor(mContext.getColor(R.color.system_notification_accent_color))
+                        .setContentTitle(title)
+                        .setContentText(text)
+                        .setContentIntent(buildForgetPendingIntent(rec))
+                        .setStyle(new Notification.BigTextStyle().bigText(text))
+                        .setVisibility(Notification.VISIBILITY_PUBLIC)
+                        .setLocalOnly(true)
+                        .setCategory(Notification.CATEGORY_SYSTEM)
+                        .setOngoing(true)
+                        .build();
+
+                mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
+            }
         }
     }
 
-    public void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) {
-        // We only care about public volumes
-        if (vol.getType() != VolumeInfo.TYPE_PUBLIC) {
-            return;
-        }
+    private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
+        if (volumeCount == 0) {
+            // No supported volumes found, give user option to format
+            final CharSequence title = mContext.getString(
+                    R.string.ext_media_unmountable_notification_title, disk.getDescription());
+            final CharSequence text = mContext.getString(
+                    R.string.ext_media_unmountable_notification_message, disk.getDescription());
 
-        Log.d(TAG, vol.toString());
+            final Notification notif = new Notification.Builder(mContext)
+                    .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
+                    .setColor(mContext.getColor(R.color.system_notification_accent_color))
+                    .setContentTitle(title)
+                    .setContentText(text)
+                    .setContentIntent(buildInitPendingIntent(disk))
+                    .setStyle(new Notification.BigTextStyle().bigText(text))
+                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                    .setLocalOnly(true)
+                    .setCategory(Notification.CATEGORY_ERROR)
+                    .build();
+
+            mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
+
+        } else {
+            // Yay, we have volumes!
+            mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
+        }
+    }
+
+    private void onVolumeStateChangedInternal(VolumeInfo vol) {
+        switch (vol.getType()) {
+            case VolumeInfo.TYPE_PRIVATE:
+                onPrivateVolumeStateChangedInternal(vol);
+                break;
+            case VolumeInfo.TYPE_PUBLIC:
+                onPublicVolumeStateChangedInternal(vol);
+                break;
+        }
+    }
+
+    private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
+        Log.d(TAG, "Notifying about private volume: " + vol.toString());
+
+        updateMissingPrivateVolumes();
+    }
+
+    private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
+        Log.d(TAG, "Notifying about public volume: " + vol.toString());
 
         final Notification notif;
-        switch (newState) {
+        switch (vol.getState()) {
             case VolumeInfo.STATE_UNMOUNTED:
                 notif = onVolumeUnmounted(vol);
                 break;
@@ -133,9 +274,9 @@
         }
 
         if (notif != null) {
-            mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
+            mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
         } else {
-            mNotificationManager.cancelAsUser(vol.getId(), NOTIF_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
         }
     }
 
@@ -159,20 +300,24 @@
     }
 
     private Notification onVolumeMounted(VolumeInfo vol) {
+        final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
+
         // Don't annoy when user dismissed in past
-        if (vol.isSnoozed()) return null;
+        if (rec.isSnoozed()) return null;
 
         final DiskInfo disk = vol.getDisk();
-        if (disk.isAdoptable() && !vol.isInited()) {
+        if (disk.isAdoptable() && !rec.isInited()) {
             final CharSequence title = disk.getDescription();
             final CharSequence text = mContext.getString(
                     R.string.ext_media_new_notification_message, disk.getDescription());
 
+            final PendingIntent initIntent = buildInitPendingIntent(vol);
             return buildNotificationBuilder(vol, title, text)
                     .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
-                            buildInitPendingIntent(vol)))
+                            initIntent))
                     .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
                             buildUnmountPendingIntent(vol)))
+                    .setContentIntent(initIntent)
                     .setDeleteIntent(buildSnoozeIntent(vol))
                     .setCategory(Notification.CATEGORY_SYSTEM)
                     .build();
@@ -182,11 +327,13 @@
             final CharSequence text = mContext.getString(
                     R.string.ext_media_ready_notification_message, disk.getDescription());
 
+            final PendingIntent browseIntent = buildBrowsePendingIntent(vol);
             return buildNotificationBuilder(vol, title, text)
                     .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
-                            buildBrowsePendingIntent(vol)))
+                            browseIntent))
                     .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
                             buildUnmountPendingIntent(vol)))
+                    .setContentIntent(browseIntent)
                     .setDeleteIntent(buildSnoozeIntent(vol))
                     .setCategory(Notification.CATEGORY_SYSTEM)
                     .setPriority(Notification.PRIORITY_LOW)
@@ -221,7 +368,7 @@
                 R.string.ext_media_unmountable_notification_message, disk.getDescription());
 
         return buildNotificationBuilder(vol, title, text)
-                .setContentIntent(buildDetailsPendingIntent(vol))
+                .setContentIntent(buildVolumeSettingsPendingIntent(vol))
                 .setCategory(Notification.CATEGORY_ERROR)
                 .build();
     }
@@ -260,16 +407,102 @@
                 .build();
     }
 
-    private int getSmallIcon(VolumeInfo vol) {
-        if (vol.disk.isSd()) {
-            switch (vol.getState()) {
+    private void onMoveProgress(MoveInfo move, int status, long estMillis) {
+        final CharSequence title;
+        if (!TextUtils.isEmpty(move.label)) {
+            title = mContext.getString(R.string.ext_media_move_specific_title, move.label);
+        } else {
+            title = mContext.getString(R.string.ext_media_move_title);
+        }
+
+        final CharSequence text;
+        if (estMillis < 0) {
+            text = null;
+        } else {
+            text = DateUtils.formatDuration(estMillis);
+        }
+
+        final PendingIntent intent;
+        if (move.packageName != null) {
+            intent = buildWizardMovePendingIntent(move);
+        } else {
+            intent = buildWizardMigratePendingIntent(move);
+        }
+
+        final Notification notif = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.stat_notify_sdcard)
+                .setColor(mContext.getColor(R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(text)
+                .setContentIntent(intent)
+                .setStyle(new Notification.BigTextStyle().bigText(text))
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setLocalOnly(true)
+                .setCategory(Notification.CATEGORY_PROGRESS)
+                .setPriority(Notification.PRIORITY_LOW)
+                .setProgress(100, status, false)
+                .setOngoing(true)
+                .build();
+
+        mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
+    }
+
+    private void onMoveFinished(MoveInfo move, int status) {
+        if (move.packageName != null) {
+            // We currently ignore finished app moves; just clear the last
+            // published progress
+            mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL);
+            return;
+        }
+
+        final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
+        final String descrip = mStorageManager.getBestVolumeDescription(privateVol);
+
+        final CharSequence title;
+        final CharSequence text;
+        if (status == PackageManager.MOVE_SUCCEEDED) {
+            title = mContext.getString(R.string.ext_media_move_success_title);
+            text = mContext.getString(R.string.ext_media_move_success_message, descrip);
+        } else {
+            title = mContext.getString(R.string.ext_media_move_failure_title);
+            text = mContext.getString(R.string.ext_media_move_failure_message);
+        }
+
+        // Jump back into the wizard flow if we moved to a real disk
+        final PendingIntent intent;
+        if (privateVol != null && privateVol.getDisk() != null) {
+            intent = buildWizardReadyPendingIntent(privateVol.getDisk());
+        } else {
+            intent = buildVolumeSettingsPendingIntent(privateVol);
+        }
+
+        final Notification notif = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.stat_notify_sdcard)
+                .setColor(mContext.getColor(R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(text)
+                .setContentIntent(intent)
+                .setStyle(new Notification.BigTextStyle().bigText(text))
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setLocalOnly(true)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setPriority(Notification.PRIORITY_LOW)
+                .setAutoCancel(true)
+                .build();
+
+        mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
+    }
+
+    private int getSmallIcon(DiskInfo disk, int state) {
+        if (disk.isSd()) {
+            switch (state) {
                 case VolumeInfo.STATE_CHECKING:
                 case VolumeInfo.STATE_EJECTING:
                     return R.drawable.stat_notify_sdcard_prepare;
                 default:
                     return R.drawable.stat_notify_sdcard;
             }
-        } else if (vol.disk.isUsb()) {
+        } else if (disk.isUsb()) {
             return R.drawable.stat_sys_data_usb;
         } else {
             return R.drawable.stat_notify_sdcard;
@@ -279,7 +512,7 @@
     private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
             CharSequence text) {
         return new Notification.Builder(mContext)
-                .setSmallIcon(getSmallIcon(vol))
+                .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
                 .setColor(mContext.getColor(R.color.system_notification_accent_color))
                 .setContentTitle(title)
                 .setContentText(text)
@@ -288,6 +521,17 @@
                 .setLocalOnly(true);
     }
 
+    private PendingIntent buildInitPendingIntent(DiskInfo disk) {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.deviceinfo.StorageWizardInit");
+        intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
+
+        final int requestKey = disk.getId().hashCode();
+        return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
+
     private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
         final Intent intent = new Intent();
         intent.setClassName("com.android.settings",
@@ -318,10 +562,20 @@
                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
     }
 
-    private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
+    private PendingIntent buildVolumeSettingsPendingIntent(VolumeInfo vol) {
         final Intent intent = new Intent();
-        intent.setClassName("com.android.settings",
-                "com.android.settings.Settings$StorageVolumeSettingsActivity");
+        switch (vol.getType()) {
+            case VolumeInfo.TYPE_PRIVATE:
+                intent.setClassName("com.android.settings",
+                        "com.android.settings.Settings$PrivateVolumeSettingsActivity");
+                break;
+            case VolumeInfo.TYPE_PUBLIC:
+                intent.setClassName("com.android.settings",
+                        "com.android.settings.Settings$PublicVolumeSettingsActivity");
+                break;
+            default:
+                return null;
+        }
         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
 
         final int requestKey = vol.getId().hashCode();
@@ -331,10 +585,55 @@
 
     private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
         final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
-        intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+        intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
 
         final int requestKey = vol.getId().hashCode();
         return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
                 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
     }
+
+    private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.Settings$PrivateVolumeForgetActivity");
+        intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
+
+        final int requestKey = rec.getFsUuid().hashCode();
+        return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
+
+    private PendingIntent buildWizardMigratePendingIntent(MoveInfo move) {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.deviceinfo.StorageWizardMigrateProgress");
+        intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
+
+        final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid);
+        intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+
+        return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
+
+    private PendingIntent buildWizardMovePendingIntent(MoveInfo move) {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.deviceinfo.StorageWizardMoveProgress");
+        intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
+
+        return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
+
+    private PendingIntent buildWizardReadyPendingIntent(DiskInfo disk) {
+        final Intent intent = new Intent();
+        intent.setClassName("com.android.settings",
+                "com.android.settings.deviceinfo.StorageWizardReady");
+        intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
+
+        final int requestKey = disk.getId().hashCode();
+        return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index 4f20ac7..f7cb9fe 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -17,6 +17,7 @@
 package com.android.systemui.volume;
 
 import android.content.Context;
+import android.graphics.Typeface;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -30,6 +31,8 @@
 
 public class SegmentedButtons extends LinearLayout {
     private static final int LABEL_RES_KEY = R.id.label;
+    private static final Typeface REGULAR = Typeface.create("sans-serif", Typeface.NORMAL);
+    private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL);
 
     private final Context mContext;
     private final LayoutInflater mInflater;
@@ -60,6 +63,7 @@
             final Object tag = c.getTag();
             final boolean selected = Objects.equals(mSelectedValue, tag);
             c.setSelected(selected);
+            c.setTypeface(selected ? MEDIUM : REGULAR);
         }
         fireOnSelected();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java
index 216a4da..4214091 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Util.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java
@@ -144,9 +144,14 @@
         return HMMAA.format(new Date(millis));
     }
 
-    public static void setText(TextView tv, CharSequence text) {
-        if (Objects.equals(tv.getText(), text)) return;
+    private static CharSequence emptyToNull(CharSequence str) {
+        return str == null || str.length() == 0 ? null : str;
+    }
+
+    public static boolean setText(TextView tv, CharSequence text) {
+        if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false;
         tv.setText(text);
+        return true;
     }
 
     public static final void setVisOrGone(View v, boolean vis) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index bb4aa61..9434036 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -37,7 +37,6 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.provider.Settings.Global;
-import android.service.notification.ZenModeConfig;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseBooleanArray;
@@ -52,7 +51,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.animation.DecelerateInterpolator;
-import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
@@ -90,16 +88,12 @@
     private final ViewGroup mDialogView;
     private final ViewGroup mDialogContentView;
     private final ImageButton mExpandButton;
-    private final TextView mFootlineText;
-    private final Button mFootlineAction;
     private final View mSettingsButton;
-    private final View mFooter;
     private final List<VolumeRow> mRows = new ArrayList<VolumeRow>();
     private final SpTexts mSpTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
     private final KeyguardManager mKeyguard;
     private final int mExpandButtonAnimationDuration;
-    private final View mTextFooter;
     private final ZenFooter mZenFooter;
     private final LayoutTransition mLayoutTransition;
     private final Object mSafetyWarningLock = new Object();
@@ -108,8 +102,6 @@
     private boolean mExpanded;
     private int mActiveStream;
     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;
@@ -118,7 +110,7 @@
     private SafetyWarningDialog mSafetyWarning;
     private Callback mCallback;
 
-    public VolumeDialog(Context context, VolumeDialogController controller,
+    public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
             ZenModeController zenModeController, Callback callback) {
         mContext = context;
         mController = controller;
@@ -141,7 +133,7 @@
         mDialog.setCanceledOnTouchOutside(true);
         final Resources res = mContext.getResources();
         final WindowManager.LayoutParams lp = window.getAttributes();
-        lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+        lp.type = windowType;
         lp.format = PixelFormat.TRANSLUCENT;
         lp.setTitle(VolumeDialog.class.getSimpleName());
         lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
@@ -176,17 +168,11 @@
         addRow(AudioManager.STREAM_SYSTEM,
                 R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
 
-        mTextFooter = mDialog.findViewById(R.id.volume_text_footer);
-        mFootlineText = (TextView) mDialog.findViewById(R.id.volume_footline_text);
-        mSpTexts.add(mFootlineText);
-        mFootlineAction = (Button) mDialog.findViewById(R.id.volume_footline_action_button);
-        mSpTexts.add(mFootlineAction);
-        mFooter = mDialog.findViewById(R.id.volume_footer);
         mSettingsButton = mDialog.findViewById(R.id.volume_settings_button);
         mSettingsButton.setOnClickListener(mClickSettings);
         mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
         mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
-        mZenFooter.init(zenModeController, mZenFooterCallback);
+        mZenFooter.init(zenModeController);
 
         controller.addCallback(mControllerCallbackH, mHandler);
         controller.getState();
@@ -217,18 +203,6 @@
         mHandler.sendEmptyMessage(H.RECHECK_ALL);
     }
 
-    public void setShowFooter(boolean show) {
-        if (mShowFooter == show) return;
-        mShowFooter = show;
-        mHandler.sendEmptyMessage(H.RECHECK_ALL);
-    }
-
-    public void setZenFooter(boolean zen) {
-        if (mShowZenFooter == zen) return;
-        mShowZenFooter = zen;
-        mHandler.sendEmptyMessage(H.RECHECK_ALL);
-    }
-
     public void setAutomute(boolean automute) {
         if (mAutomute == automute) return;
         mAutomute = automute;
@@ -315,7 +289,6 @@
         writer.print("  mActiveStream: "); writer.println(mActiveStream);
         writer.print("  mDynamic: "); writer.println(mDynamic);
         writer.print("  mShowHeaders: "); writer.println(mShowHeaders);
-        writer.print("  mShowFooter: "); writer.println(mShowFooter);
         writer.print("  mAutomute: "); writer.println(mAutomute);
         writer.print("  mSilentMode: "); writer.println(mSilentMode);
     }
@@ -444,7 +417,6 @@
     }
 
     private int computeTimeoutH() {
-        if (mZenFooter != null && mZenFooter.isFooterExpanded()) return 10000;
         if (mSafetyWarning != null) return 5000;
         if (mExpanded || mExpanding) return 5000;
         if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
@@ -515,18 +487,9 @@
         final VolumeRow activeRow = getActiveRow();
         updateFooterH();
         updateExpandButtonH();
-        final boolean footerVisible = mFooter.getVisibility() == View.VISIBLE;
         if (!mShowing) {
             trimObsoleteH();
         }
-        // first, find the last visible row
-        VolumeRow lastVisible = null;
-        for (VolumeRow row : mRows) {
-            final boolean isActive = row == activeRow;
-            if (isVisibleH(row, isActive)) {
-                lastVisible = row;
-            }
-        }
         // apply changes to all rows
         for (VolumeRow row : mRows) {
             final boolean isActive = row == activeRow;
@@ -542,8 +505,7 @@
                     row.settingsButton.setImageResource(expandButtonRes);
                 }
             }
-            Util.setVisOrInvis(row.settingsButton,
-                     mExpanded && (!footerVisible && row == lastVisible));
+            Util.setVisOrInvis(row.settingsButton, false);
             row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
         }
     }
@@ -585,51 +547,9 @@
         updateFooterH();
     }
 
-    private void updateTextFooterH() {
-        final boolean zen = mState.zenMode != Global.ZEN_MODE_OFF;
-        final boolean wasVisible = mFooter.getVisibility() == View.VISIBLE;
-        Util.setVisOrGone(mTextFooter, mExpanded && mShowFooter && (zen || mShowing && wasVisible));
-        if (mTextFooter.getVisibility() == View.VISIBLE) {
-            String text = null;
-            String action = null;
-            if (mState.exitCondition != null) {
-                final long countdown = ZenModeConfig.tryParseCountdownConditionId(mState
-                        .exitCondition.id);
-                if (countdown != 0) {
-                    text = mContext.getString(R.string.volume_dnd_ends_at,
-                            Util.getShortTime(countdown));
-                    action = mContext.getString(R.string.volume_end_now);
-                }
-            }
-            if (text == null) {
-                text = mContext.getString(R.string.volume_dnd_is_on);
-            }
-            if (action == null) {
-                action = mContext.getString(R.string.volume_turn_off);
-            }
-            Util.setText(mFootlineText, text);
-            Util.setText(mFootlineAction, action);
-            mFootlineAction.setOnClickListener(mTurnOffDnd);
-        }
-        Util.setVisOrGone(mFootlineText, zen);
-        Util.setVisOrGone(mFootlineAction, zen);
-    }
-
     private void updateFooterH() {
-        if (!mShowFooter) {
-            Util.setVisOrGone(mFooter, false);
-            return;
-        }
-        if (mShowZenFooter) {
-            Util.setVisOrGone(mTextFooter, false);
-            final boolean ringActive = mActiveStream == AudioManager.STREAM_RING;
-            Util.setVisOrGone(mZenFooter, mZenFooter.isZen() && ringActive
-                    || mShowing && (mExpanded || mZenFooter.getVisibility() == View.VISIBLE));
-            mZenFooter.update();
-        } else {
-            Util.setVisOrGone(mZenFooter, false);
-            updateTextFooterH();
-        }
+        Util.setVisOrGone(mZenFooter, mState.zenMode != Global.ZEN_MODE_OFF);
+        mZenFooter.update();
     }
 
     private void updateVolumeRowH(VolumeRow row) {
@@ -642,12 +562,20 @@
         }
         final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
         final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
+        final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
+        final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
         final boolean isRingVibrate = isRingStream
                 && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
-        final boolean isNoned = (isRingStream || isSystemStream)
-                && mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
-        final boolean isLimited = isRingStream
-                && mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        final boolean isRingSilent = isRingStream
+                && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
+        final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
+        final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        final boolean isZenPriority = mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        final boolean isRingZenNone = (isRingStream || isSystemStream) && isZenNone;
+        final boolean isRingLimited = isRingStream && isZenPriority;
+        final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
+                : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream)
+                : false;
 
         // update slider max
         final int max = ss.levelMax * 100;
@@ -663,15 +591,15 @@
 
         // update header text
         final String text;
-        if (isNoned) {
+        if (isRingZenNone) {
             text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name);
-        } else if (isRingVibrate && isLimited) {
+        } else if (isRingVibrate && isRingLimited) {
             text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name);
         } else if (isRingVibrate) {
             text = mContext.getString(R.string.volume_stream_vibrate, ss.name);
         } else if (ss.muted || mAutomute && ss.level == 0) {
             text = mContext.getString(R.string.volume_stream_muted, ss.name);
-        } else if (isLimited) {
+        } else if (isRingLimited) {
             text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name);
         } else {
             text = ss.name;
@@ -679,11 +607,12 @@
         Util.setText(row.header, text);
 
         // update icon
-        final boolean iconEnabled = mAutomute || ss.muteSupported;
+        final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
         row.icon.setEnabled(iconEnabled);
         row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
         final int iconRes =
                 isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
+                : isRingSilent || zenMuted ? row.cachedIconRes
                 : ss.routedToBluetooth ?
                         (ss.muted ? R.drawable.ic_volume_media_bt_mute
                                 : R.drawable.ic_volume_media_bt)
@@ -705,10 +634,11 @@
                 : Events.ICON_STATE_UNKNOWN;
 
         // update slider
-        updateVolumeRowSliderH(row);
+        updateVolumeRowSliderH(row, zenMuted);
     }
 
-    private void updateVolumeRowSliderH(VolumeRow row) {
+    private void updateVolumeRowSliderH(VolumeRow row, boolean zenMuted) {
+        row.slider.setEnabled(!zenMuted);
         if (row.tracking) {
             return;  // don't update if user is sliding
         }
@@ -887,46 +817,6 @@
         }
     };
 
-    private final View.OnClickListener mTurnOffDnd = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            mSettingsButton.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mController.setZenMode(Global.ZEN_MODE_OFF);
-                }
-            }, WAIT_FOR_RIPPLE);
-        }
-    };
-
-    private final ZenFooter.Callback mZenFooterCallback = new ZenFooter.Callback() {
-        @Override
-        public void onFooterExpanded() {
-            mHandler.sendEmptyMessage(H.RESCHEDULE_TIMEOUT);
-        }
-
-        @Override
-        public void onSettingsClicked() {
-            dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED);
-            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 {
         private static final int SHOW = 1;
         private static final int DISMISS = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 86abfcc..1083f40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
+import android.view.WindowManager;
 
 import com.android.systemui.SystemUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -61,7 +62,8 @@
             }
         };
         mZenModeController = zen;
-        mDialog = new VolumeDialog(context, mController, zen, mVolumeDialogCallback);
+        mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY,
+                mController, zen, mVolumeDialogCallback);
         applyConfiguration();
     }
 
@@ -76,12 +78,10 @@
         mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true);
         mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
         mDialog.setShowHeaders(false);
-        mDialog.setShowFooter(true);
-        mDialog.setZenFooter(true);
         mDialog.setAutomute(true);
         mDialog.setSilentMode(false);
         mController.setVolumePolicy(mVolumePolicy);
-        mController.showDndTile(false);
+        mController.showDndTile(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 012eb41..3a8081f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -100,7 +100,7 @@
     private boolean mEnabled;
     private boolean mDestroyed;
     private VolumePolicy mVolumePolicy;
-    private boolean mShowDndTile = false;
+    private boolean mShowDndTile = true;
 
     public VolumeDialogController(Context context, ComponentName component) {
         mContext = context.getApplicationContext();
@@ -125,6 +125,10 @@
         return mAudio;
     }
 
+    public ZenModeConfig getZenModeConfig() {
+        return mNoMan.getZenModeConfig();
+    }
+
     public void dismiss() {
         mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
     }
@@ -342,7 +346,7 @@
         updateRingerModeExternalW(mAudio.getRingerMode());
         updateZenModeW();
         updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
-        updateExitConditionW();
+        updateZenModeConfigW();
         mCallbacks.onStateChanged(mState);
     }
 
@@ -395,17 +399,10 @@
         return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
     }
 
-    private Condition getExitCondition() {
-        final ZenModeConfig config = mNoMan.getZenModeConfig();
-        return config == null ? null
-                : config.manualRule == null ? null
-                : config.manualRule.condition;
-    }
-
-    private boolean updateExitConditionW() {
-        final Condition exitCondition = getExitCondition();
-        if (Objects.equals(mState.exitCondition, exitCondition)) return false;
-        mState.exitCondition = exitCondition;
+    private boolean updateZenModeConfigW() {
+        final ZenModeConfig zenModeConfig = getZenModeConfig();
+        if (Objects.equals(mState.zenModeConfig, zenModeConfig)) return false;
+        mState.zenModeConfig = zenModeConfig;
         return true;
     }
 
@@ -750,7 +747,7 @@
                 changed = updateZenModeW();
             }
             if (ZEN_MODE_CONFIG_URI.equals(uri)) {
-                changed = updateExitConditionW();
+                changed = updateZenModeConfigW();
             }
             if (changed) {
                 mCallbacks.onStateChanged(mState);
@@ -943,7 +940,7 @@
         public int zenMode;
         public ComponentName effectsSuppressor;
         public String effectsSuppressorName;
-        public Condition exitCondition;
+        public ZenModeConfig zenModeConfig;
         public int activeStream = NO_ACTIVE_STREAM;
 
         public State copy() {
@@ -956,7 +953,7 @@
             rt.zenMode = zenMode;
             if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone();
             rt.effectsSuppressorName = effectsSuppressorName;
-            if (exitCondition != null) rt.exitCondition = exitCondition.copy();
+            if (zenModeConfig != null) rt.zenModeConfig = zenModeConfig.copy();
             rt.activeStream = activeStream;
             return rt;
         }
@@ -977,10 +974,15 @@
             sb.append(",zenMode:").append(zenMode);
             sb.append(",effectsSuppressor:").append(effectsSuppressor);
             sb.append(",effectsSuppressorName:").append(effectsSuppressorName);
-            sb.append(",exitCondition:").append(exitCondition);
+            sb.append(",zenModeConfig:").append(zenModeConfig);
             sb.append(",activeStream:").append(activeStream);
             return sb.append('}').toString();
         }
+
+        public Condition getManualExitCondition() {
+            return zenModeConfig != null && zenModeConfig.manualRule != null
+                    ? zenModeConfig.manualRule.condition : null;
+        }
     }
 
     public interface Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 915e998..04339eb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -32,8 +32,6 @@
     public static final String PREF_SHOW_HEADERS = "pref_show_headers";
     public static final String PREF_SHOW_FAKE_REMOTE_1 = "pref_show_fake_remote_1";
     public static final String PREF_SHOW_FAKE_REMOTE_2 = "pref_show_fake_remote_2";
-    public static final String PREF_SHOW_FOOTER = "pref_show_footer";
-    public static final String PREF_ZEN_FOOTER = "pref_zen_footer";
     public static final String PREF_ENABLE_AUTOMUTE = "pref_enable_automute";
     public static final String PREF_ENABLE_SILENT_MODE = "pref_enable_silent_mode";
     public static final String PREF_DEBUG_LOGGING = "pref_debug_logging";
@@ -46,10 +44,8 @@
     public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
 
     public static final boolean DEFAULT_SHOW_HEADERS = true;
-    public static final boolean DEFAULT_SHOW_FOOTER = true;
     public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
     public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
-    public static final boolean DEFAULT_ZEN_FOOTER = true;
 
     public static void unregisterCallbacks(Context c, OnSharedPreferenceChangeListener listener) {
         prefs(c).unregisterOnSharedPreferenceChangeListener(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 5f04aaf..2688813 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -103,7 +103,7 @@
 
     private void setDefaultVolumeController(boolean register) {
         if (register) {
-            DndTile.setVisible(mContext, false);
+            DndTile.setVisible(mContext, true);
             if (LOGD) Log.d(TAG, "Registering default volume controller");
             getVolumeComponent().register();
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index 775c87d..8aded45 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -16,20 +16,12 @@
 package com.android.systemui.volume;
 
 import android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.res.Resources;
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
 import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.LinearLayout;
-import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.systemui.R;
@@ -38,70 +30,36 @@
 import java.util.Objects;
 
 /**
- * Switch bar + zen mode panel (conditions) attached to the bottom of the volume dialog.
+ * Zen mode information (and end button) attached to the bottom of the volume dialog.
  */
 public class ZenFooter extends LinearLayout {
     private static final String TAG = Util.logTag(ZenFooter.class);
 
     private final Context mContext;
-    private final float mSecondaryAlpha;
-    private final LayoutTransition mLayoutTransition;
 
-    private ZenModeController mController;
-    private Switch mSwitch;
-    private ZenModePanel mZenModePanel;
-    private View mZenModePanelButtons;
-    private View mZenModePanelMoreButton;
-    private View mZenModePanelDoneButton;
-    private View mSwitchBar;
-    private View mSwitchBarIcon;
-    private View mSummary;
     private TextView mSummaryLine1;
     private TextView mSummaryLine2;
-    private boolean mFooterExpanded;
+    private View mEndNowButton;
     private int mZen = -1;
     private ZenModeConfig mConfig;
-    private Callback mCallback;
+    private ZenModeController mController;
 
     public ZenFooter(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
-        mSecondaryAlpha = getFloat(context.getResources(), R.dimen.volume_secondary_alpha);
-        mLayoutTransition = new LayoutTransition();
-        mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
-        mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
-        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-    }
-
-    private static float getFloat(Resources r, int resId) {
-        final TypedValue tv = new TypedValue();
-        r.getValue(resId, tv, true);
-        return tv.getFloat();
+        setLayoutTransition(new LayoutTransition());
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mSwitchBar = findViewById(R.id.volume_zen_switch_bar);
-        mSwitchBarIcon = findViewById(R.id.volume_zen_switch_bar_icon);
-        mSwitch = (Switch) findViewById(R.id.volume_zen_switch);
-        mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
-        mZenModePanelButtons = findViewById(R.id.volume_zen_mode_panel_buttons);
-        mZenModePanelMoreButton = findViewById(R.id.volume_zen_mode_panel_more);
-        mZenModePanelDoneButton = findViewById(R.id.volume_zen_mode_panel_done);
-        mSummary = findViewById(R.id.volume_zen_panel_summary);
-        mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_1);
-        mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_2);
+        mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_summary_line_1);
+        mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_summary_line_2);
+        mEndNowButton = findViewById(R.id.volume_zen_end_now);
     }
 
-    public void init(ZenModeController controller, Callback callback) {
-        mCallback = callback;
-        mController = controller;
-        mZenModePanel.init(controller);
-        mZenModePanel.setEmbedded(true);
-        mZenModePanel.setCallback(mZenModePanelCallback);
-        mSwitch.setOnCheckedChangeListener(mCheckedListener);
-        mController.addCallback(new ZenModeController.Callback() {
+    public void init(final ZenModeController controller) {
+        controller.addCallback(new ZenModeController.Callback() {
             @Override
             public void onZenChanged(int zen) {
                 setZen(zen);
@@ -111,30 +69,15 @@
                 setConfig(config);
             }
         });
-        mSwitchBar.setOnClickListener(new OnClickListener() {
+        mEndNowButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                mSwitch.setChecked(!mSwitch.isChecked());
+                controller.setZen(Global.ZEN_MODE_OFF, null, TAG);
             }
         });
-        mZenModePanelMoreButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mCallback != null) {
-                    mCallback.onSettingsClicked();
-                }
-            }
-        });
-        mZenModePanelDoneButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mCallback != null) {
-                    mCallback.onDoneClicked();
-                }
-            }
-        });
-        mZen = mController.getZen();
-        mConfig = mController.getConfig();
+        mZen = controller.getZen();
+        mConfig = controller.getConfig();
+        mController = controller;
         update();
     }
 
@@ -166,96 +109,17 @@
         return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        setLayoutTransition(null);
-        setFooterExpanded(false);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        setLayoutTransition(mLayoutTransition);
-    }
-
-    private boolean setFooterExpanded(boolean expanded) {
-        if (mFooterExpanded == expanded) return false;
-        mFooterExpanded = expanded;
-        update();
-        if (mCallback != null) {
-            mCallback.onFooterExpanded();
-        }
-        return true;
-    }
-
-    public boolean isFooterExpanded() {
-        return mFooterExpanded;
-    }
-
     public void update() {
-        final boolean isZen = isZen();
-        mSwitch.setOnCheckedChangeListener(null);
-        mSwitch.setChecked(isZen);
-        mSwitch.setOnCheckedChangeListener(mCheckedListener);
-        Util.setVisOrGone(mZenModePanel, isZen && mFooterExpanded);
-        Util.setVisOrGone(mZenModePanelButtons, isZen && mFooterExpanded);
-        Util.setVisOrGone(mSummary, isZen && !mFooterExpanded);
-        mSwitchBarIcon.setAlpha(isZen ? 1 : mSecondaryAlpha);
         final String line1 =
                 isZenPriority() ? mContext.getString(R.string.interruption_level_priority)
                 : isZenAlarms() ? mContext.getString(R.string.interruption_level_alarms)
                 : isZenNone() ? mContext.getString(R.string.interruption_level_none)
                 : null;
         Util.setText(mSummaryLine1, line1);
+
         final String line2 = ZenModeConfig.getConditionSummary(mContext, mConfig,
-                ActivityManager.getCurrentUser());
+                mController.getCurrentUser());
         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_ALARMS : Global.ZEN_MODE_OFF;
-                mZen = newZen;  // this one's optimistic
-                setFooterExpanded(isChecked);
-                mController.setZen(newZen, null, TAG);
-            }
-        }
-    };
-
-    public interface Callback {
-        void onFooterExpanded();
-        void onSettingsClicked();
-        void onDoneClicked();
-        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 1b563dc..9f9c9ac 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -41,8 +41,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.ImageView;
@@ -85,22 +83,14 @@
     private final H mHandler = new H();
     private final ZenPrefs mPrefs;
     private final IconPulser mIconPulser;
-    private final int mSubheadWarningColor;
-    private final int mSubheadColor;
-    private final Interpolator mInterpolator;
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
     private final Uri mForeverId;
 
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
     private SegmentedButtons mZenButtons;
-    private ViewGroup mZenButtonsContainer;
-    private View mZenSubhead;
-    private TextView mZenSubheadCollapsed;
-    private TextView mZenSubheadExpanded;
-    private View mZenEmbeddedDivider;
-    private View mMoreSettings;
     private View mZenIntroduction;
+    private TextView mZenIntroductionMessage;
     private View mZenIntroductionConfirm;
     private View mZenIntroductionCustomize;
     private LinearLayout mZenConditions;
@@ -113,7 +103,6 @@
     private int mFirstConditionIndex;
     private boolean mRequestingConditions;
     private Condition mExitCondition;
-    private String mExitConditionText;
     private int mBucketIndex = -1;
     private boolean mExpanded;
     private boolean mHidden;
@@ -123,7 +112,6 @@
     private Condition mSessionExitCondition;
     private Condition[] mConditions;
     private Condition mTimeCondition;
-    private boolean mEmbedded;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -131,10 +119,6 @@
         mPrefs = new ZenPrefs();
         mInflater = LayoutInflater.from(mContext.getApplicationContext());
         mIconPulser = new IconPulser(mContext);
-        mSubheadWarningColor = context.getColor(R.color.system_warning_color);
-        mSubheadColor = context.getColor(R.color.qs_subhead);
-        mInterpolator = AnimationUtils.loadInterpolator(mContext,
-                com.android.internal.R.interpolator.fast_out_slow_in);
         mForeverId = Condition.newId(mContext).appendPath("forever").build();
         if (DEBUG) Log.d(mTag, "new ZenModePanel");
     }
@@ -149,25 +133,13 @@
         pw.print("  mExpanded="); pw.println(mExpanded);
         pw.print("  mSessionZen="); pw.println(mSessionZen);
         pw.print("  mAttachedZen="); pw.println(mAttachedZen);
-        pw.print("  mEmbedded="); pw.println(mEmbedded);
+        pw.print("  mConfirmedPriorityIntroduction=");
+        pw.println(mPrefs.mConfirmedPriorityIntroduction);
+        pw.print("  mConfirmedSilenceIntroduction=");
+        pw.println(mPrefs.mConfirmedSilenceIntroduction);
         mTransitionHelper.dump(fd, pw, args);
     }
 
-    public void setEmbedded(boolean embedded) {
-        if (mEmbedded == embedded) return;
-        mEmbedded = embedded;
-        mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
-        setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
-        if (mEmbedded) {
-            mZenButtonsContainer.setBackground(null);
-        } else {
-            mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
-        }
-        mZenButtons.getChildAt(3).setVisibility(mEmbedded ? GONE : VISIBLE);
-        mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
-        updateWidgets();
-    }
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -179,37 +151,10 @@
                 Global.ZEN_MODE_ALARMS);
         mZenButtons.addButton(R.string.interruption_level_priority_twoline,
                 Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-        mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
         mZenButtons.setCallback(mZenButtonsCallback);
 
-        mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
-        mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
-
-        mZenSubhead = findViewById(R.id.zen_subhead);
-        mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
-
-        mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
-        mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setExpanded(true);
-            }
-        });
-        Interaction.register(mZenSubheadCollapsed, mInteractionCallback);
-
-        mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded);
-        Interaction.register(mZenSubheadExpanded, mInteractionCallback);
-
-        mMoreSettings = findViewById(R.id.zen_more_settings);
-        mMoreSettings.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                fireMoreSettings();
-            }
-        });
-        Interaction.register(mMoreSettings, mInteractionCallback);
-
         mZenIntroduction = findViewById(R.id.zen_introduction);
+        mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message);
         mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
         mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
             @Override
@@ -230,25 +175,25 @@
 
         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);
+        final String prefKey = prefKeyForConfirmation(getSelectedZen(Global.ZEN_MODE_OFF));
+        if (prefKey == null) return;
+        if (DEBUG) Log.d(TAG, "confirmZenIntroduction " + prefKey);
+        Prefs.putBoolean(mContext, prefKey, true);
         mHandler.sendEmptyMessage(H.UPDATE_WIDGETS);
     }
 
-    private LayoutTransition newLayoutTransition(TransitionListener listener) {
-        final LayoutTransition transition = new LayoutTransition();
-        transition.disableTransitionType(LayoutTransition.DISAPPEARING);
-        transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-        transition.disableTransitionType(LayoutTransition.APPEARING);
-        transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, mInterpolator);
-        if (listener != null) {
-            transition.addTransitionListener(listener);
+    private static String prefKeyForConfirmation(int zen) {
+        switch (zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION;
+            default:
+                return null;
         }
-        return transition;
     }
 
     @Override
@@ -260,7 +205,6 @@
         mSessionZen = mAttachedZen;
         mTransitionHelper.clear();
         setSessionExitCondition(copy(mExitCondition));
-        refreshExitConditionText();
         updateWidgets();
         setRequestingConditions(!mHidden);
     }
@@ -274,9 +218,6 @@
         mAttachedZen = -1;
         mSessionZen = -1;
         setSessionExitCondition(null);
-        if (!mEmbedded) {
-            setExpanded(false);
-        }
         setRequestingConditions(false);
         mTransitionHelper.clear();
     }
@@ -359,7 +300,6 @@
         for (int i = 0; i < mMaxConditions; i++) {
             mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
         }
-        refreshExitConditionText();
         mSessionZen = getSelectedZen(-1);
         handleUpdateManualRule(mController.getManualRule());
         if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
@@ -375,7 +315,6 @@
         if (Objects.equals(mExitCondition, exitCondition)) return;
         mExitCondition = exitCondition;
         if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
-        refreshExitConditionText();
         updateWidgets();
     }
 
@@ -395,10 +334,6 @@
         return condition == null ? null : condition.copy();
     }
 
-    private void refreshExitConditionText() {
-        mExitConditionText = getExitConditionText(mContext, mExitCondition);
-    }
-
     public static String getExitConditionText(Context context, Condition exitCondition) {
         if (exitCondition == null) {
             return foreverSummary(context);
@@ -430,7 +365,7 @@
 
     private void handleUpdateZen(int zen) {
         if (mSessionZen != -1 && mSessionZen != zen) {
-            setExpanded(mEmbedded && isShown() || !mEmbedded && zen != Global.ZEN_MODE_OFF);
+            setExpanded(isShown());
             mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
@@ -480,30 +415,18 @@
             return;
         }
         final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
-        final boolean zenOff = zen == Global.ZEN_MODE_OFF;
         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;
+        final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction
+                        || zenNone && !mPrefs.mConfirmedSilenceIntroduction);
 
         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(conditions ? VISIBLE : GONE);
-
-        if (zenNone) {
-            mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning);
-            mZenSubheadCollapsed.setText(mExitConditionText);
-        } else if (zenImportant) {
-            mZenSubheadExpanded.setText(R.string.zen_important_interruptions);
-            mZenSubheadCollapsed.setText(mExitConditionText);
-        }
-        mZenSubheadExpanded.setTextColor(zenNone && mPrefs.isNoneDangerous()
-                ? mSubheadWarningColor : mSubheadColor);
         mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
+        if (introduction) {
+            mZenIntroductionMessage.setText(zenImportant ? R.string.zen_priority_introduction
+                    : R.string.zen_silence_introduction);
+            mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
+        }
     }
 
     private static Condition parseExistingTimeCondition(Context context, Condition condition) {
@@ -761,13 +684,13 @@
         String modeText;
         switch(zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
-                modeText = mContext.getString(R.string.zen_important_interruptions);
+                modeText = mContext.getString(R.string.interruption_level_priority);
                 break;
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
-                modeText = mContext.getString(R.string.zen_no_interruptions);
+                modeText = mContext.getString(R.string.interruption_level_none);
                 break;
             case Global.ZEN_MODE_ALARMS:
-                modeText = mContext.getString(R.string.zen_alarms);
+                modeText = mContext.getString(R.string.interruption_level_alarms);
                 break;
             default:
                 return;
@@ -837,12 +760,6 @@
         setSessionExitCondition(copy(condition));
     }
 
-    private void fireMoreSettings() {
-        if (mCallback != null) {
-            mCallback.onMoreSettings();
-        }
-    }
-
     private void fireInteraction() {
         if (mCallback != null) {
             mCallback.onInteraction();
@@ -887,7 +804,6 @@
     }
 
     public interface Callback {
-        void onMoreSettings();
         void onPrioritySettings();
         void onInteraction();
         void onExpanded(boolean expanded);
@@ -907,7 +823,8 @@
 
         private int mMinuteIndex;
         private int mNoneSelected;
-        private boolean mConfirmedIntroduction;
+        private boolean mConfirmedPriorityIntroduction;
+        private boolean mConfirmedSilenceIntroduction;
 
         private ZenPrefs() {
             mNoneDangerousThreshold = mContext.getResources()
@@ -915,11 +832,8 @@
             Prefs.registerListener(mContext, this);
             updateMinuteIndex();
             updateNoneSelected();
-            updateConfirmedIntroduction();
-        }
-
-        public boolean isNoneDangerous() {
-            return mNoneSelected < mNoneDangerousThreshold;
+            updateConfirmedPriorityIntroduction();
+            updateConfirmedSilenceIntroduction();
         }
 
         public void trackNoneSelected() {
@@ -945,7 +859,8 @@
         public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
             updateMinuteIndex();
             updateNoneSelected();
-            updateConfirmedIntroduction();
+            updateConfirmedPriorityIntroduction();
+            updateConfirmedSilenceIntroduction();
         }
 
         private void updateMinuteIndex() {
@@ -968,12 +883,22 @@
             return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE);
         }
 
-        private void updateConfirmedIntroduction() {
+        private void updateConfirmedPriorityIntroduction() {
             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);
+            if (confirmed == mConfirmedPriorityIntroduction) return;
+            mConfirmedPriorityIntroduction = confirmed;
+            if (DEBUG) Log.d(mTag, "Confirmed priority introduction: "
+                    + mConfirmedPriorityIntroduction);
+        }
+
+        private void updateConfirmedSilenceIntroduction() {
+            final boolean confirmed =  Prefs.getBoolean(mContext,
+                    Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION, false);
+            if (confirmed == mConfirmedSilenceIntroduction) return;
+            mConfirmedSilenceIntroduction = confirmed;
+            if (DEBUG) Log.d(mTag, "Confirmed silence introduction: "
+                    + mConfirmedSilenceIntroduction);
         }
     }
 
@@ -981,12 +906,16 @@
         @Override
         public void onSelected(final Object value) {
             if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
-                if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
+                final int zen = (Integer) value;
+                if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
                 final Uri realConditionId = getRealConditionId(mSessionExitCondition);
                 AsyncTask.execute(new Runnable() {
                     @Override
                     public void run() {
-                        mController.setZen((Integer) value, realConditionId, TAG + ".selectZen");
+                        mController.setZen(zen, realConditionId, TAG + ".selectZen");
+                        if (zen != Global.ZEN_MODE_OFF) {
+                            Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, zen);
+                        }
                     }
                 });
             }
diff --git a/preloaded-classes b/preloaded-classes
index c94623a..d2ed762 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1152,6 +1152,7 @@
 android.provider.Settings$System
 android.provider.Telephony$Mms
 android.renderscript.RenderScript
+android.security.AndroidKeyStoreBCWorkaroundProvider
 android.security.AndroidKeyStoreProvider
 android.speech.tts.TextToSpeechService
 android.speech.tts.TextToSpeechService$SpeechItemV1
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
index 6cfdfee..5e28d3f 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -241,7 +241,7 @@
     }
 
     static void validateUplo(@Uplo int Uplo) {
-        if (Uplo != LEFT && Uplo != RIGHT) {
+        if (Uplo != UPPER && Uplo != LOWER) {
             throw new RSRuntimeException("Invalid uplo passed to BLAS");
         }
     }
@@ -276,36 +276,36 @@
             expectedYDim = 1 + (N - 1) * incY;
         }
         if (X.getType().getX() != expectedXDim ||
-            Y.getType().getY() != expectedXDim) {
+            Y.getType().getX() != expectedYDim) {
             throw new RSRuntimeException("Incorrect vector dimensions for GEMV");
         }
     }
-    void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+    public void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
         validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+    public void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
         validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+    public void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
         validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+    public void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
         validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
 
-    void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+    public void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
         // GBMV has the same validation requirements as GEMV + KL and KU >= 0
         validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
         if (KL < 0 || KU < 0) {
@@ -315,7 +315,7 @@
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, KL, KU);
     }
-    void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+    public void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
         // GBMV has the same validation requirements as GEMV + KL and KU >= 0
         validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
         if (KL < 0 || KU < 0) {
@@ -325,7 +325,7 @@
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, KL, KU);
     }
-    void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+    public void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
         // GBMV has the same validation requirements as GEMV + KL and KU >= 0
         validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
         if (KL < 0 || KU < 0) {
@@ -335,7 +335,7 @@
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, KL, KU);
     }
-    void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+    public void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
         // GBMV has the same validation requirements as GEMV + KL and KU >= 0
         validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
         if (KL < 0 || KU < 0) {
@@ -346,8 +346,10 @@
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, KL, KU);
     }
 
-    static void validateTRMV(Element e, @Transpose int TransA, Allocation A, Allocation X, int incX) {
+    static void validateTRMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
         validateTranspose(TransA);
+        validateUplo(Uplo);
+        validateDiag(Diag);
         int N = A.getType().getY();
         if (A.getType().getX() != N) {
             throw new RSRuntimeException("A must be a square matrix for TRMV");
@@ -386,158 +388,174 @@
         }
 
         int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        //is it really doing anything?
         if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
             throw new RSRuntimeException("Invalid dimension for Ap");
         }
-
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+            throw new RSRuntimeException("Incorrect vector dimensions for TPMV");
         }
 
         return N;
     }
 
-    void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+    public void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+    public void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+    public void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+    public void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV
-        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+
+    public void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV
-        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+    public void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV
-        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+    public void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV
-        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+    public void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+    public void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
         // TRSV is the same as TRMV
-        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
 
     }
-    void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+    public void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
         // TRSV is the same as TRMV
-        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
 
     }
-    void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+    public void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
         // TRSV is the same as TRMV
-        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
 
     }
-    void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+    public void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
         // TRSV is the same as TRMV
-        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
 
     }
-    void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV
-        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+    public void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         if (K < 0) {
             throw new RSRuntimeException("Number of diagonals must be positive");
         }
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV
-        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+    public void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         if (K < 0) {
             throw new RSRuntimeException("Number of diagonals must be positive");
         }
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV
-        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+    public void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         if (K < 0) {
             throw new RSRuntimeException("Number of diagonals must be positive");
         }
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV
-        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+    public void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
         int N = A.getType().getY();
         if (K < 0) {
             throw new RSRuntimeException("Number of diagonals must be positive");
         }
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         // TPSV is same as TPMV
         int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         // TPSV is same as TPMV
         int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
     }
-    void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         // TPSV is same as TPMV
         int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
     }
-    void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+    public void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
         // TPSV is same as TPMV
         int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
@@ -593,7 +611,9 @@
         if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
             throw new RSRuntimeException("Invalid dimension for Ap");
         }
-
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
             throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
@@ -622,8 +642,10 @@
         if (N < 1 || M < 1) {
             throw new RSRuntimeException("M and N must be 1 or greater for GER");
         }
-
-        int expectedXDim = 1 + (N - 1) * incX;
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (M - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
             throw new RSRuntimeException("Incorrect vector dimensions for GER");
         }
@@ -649,7 +671,9 @@
         if (N != A.getType().getY()) {
             throw new RSRuntimeException("A must be a symmetric matrix");
         }
-
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
             throw new RSRuntimeException("Incorrect vector dimensions for SYR");
@@ -674,10 +698,12 @@
         if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
             throw new RSRuntimeException("Invalid dimension for Ap");
         }
-
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+            throw new RSRuntimeException("Incorrect vector dimensions for SPR");
         }
 
         return N;
@@ -700,7 +726,9 @@
         if (N != A.getType().getY()) {
             throw new RSRuntimeException("A must be a symmetric matrix");
         }
-
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         int expectedYDim = 1 + (N - 1) * incY;
         if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
@@ -728,81 +756,91 @@
         if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
             throw new RSRuntimeException("Invalid dimension for Ap");
         }
-
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
         int expectedXDim = 1 + (N - 1) * incX;
         int expectedYDim = 1 + (N - 1) * incY;
         if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+            throw new RSRuntimeException("Incorrect vector dimensions for SPR2");
         }
 
         return N;
     }
 
-    void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+    public void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
         int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV
+    public void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
         int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
+    public void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
         int N = validateSPMV(Element.F32(mRS), Uplo, Ap, X, incX, Y, incY);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, Ap.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         int M = A.getType().getY();
         int N = A.getType().getX();
+        validateGER(Element.F32(mRS), X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sger, 0, 0, 0, 0, 0, M, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0.f, A.getID(mRS), incX, incY, 0, 0);
     }
-    void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+    public void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
         int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), A.getID(mRS), 0.f, 0, incX, 0, 0, 0);
     }
-    void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+    public void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
         int N = validateSPR(Element.F32(mRS), Uplo, X, incX, Ap);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Ap.getID(mRS), 0.f, 0, incX, 0, 0, 0);
     }
-    void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         int N = validateSYR2(Element.F32(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+    public void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
         int N = validateSPR2(Element.F32(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, Ap.getID(mRS), incX, incY, 0, 0);
     }
-    void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+    public void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
         int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV
+    public void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
         int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
+    public void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
         int N = validateSPMV(Element.F64(mRS), Uplo, Ap, X, incX, Y, incY);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, Ap.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         int M = A.getType().getY();
         int N = A.getType().getX();
+        validateGER(Element.F64(mRS), X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dger, 0, 0, 0, 0, 0, M, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0.f, A.getID(mRS), incX, incY, 0, 0);
     }
-    void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+    public void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
         int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), A.getID(mRS), 0.f, 0, incX, 0, 0, 0);
     }
-    void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+    public void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
         int N = validateSPR(Element.F64(mRS), Uplo, X, incX, Ap);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Ap.getID(mRS), 0.f, 0, incX, 0, 0, 0);
     }
-    void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         int N = validateSYR2(Element.F64(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+    public void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
         int N = validateSPR2(Element.F64(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, Ap.getID(mRS), incX, incY, 0, 0);
     }
@@ -824,8 +862,10 @@
 
         int M = A.getType().getY();
         int N = A.getType().getX();
-
-        int expectedXDim = 1 + (N - 1) * incX;
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (M - 1) * incX;
         if (X.getType().getX() != expectedXDim) {
             throw new RSRuntimeException("Incorrect vector dimensions for GERU");
         }
@@ -836,12 +876,12 @@
 
     }
 
-    void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+    public void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
         // HEMV is the same as SYR2 validation-wise
         int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+    public void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
         // HBMV is the same as SYR2 validation-wise
         int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
         if (K < 0) {
@@ -849,50 +889,50 @@
         }
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+    public void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
         // HPMV is the same as SPR2
         int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, Ap.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         // same as GERU
         validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+    public void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
         // same as SYR
-        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
+        int N = validateSYR(Element.F32_2(mRS), Uplo, X, incX, A);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, A.getID(mRS), incX, 0, 0, 0);
     }
-    void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+    public void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
         // equivalent to SPR for validation
         int N = validateSPR(Element.F32_2(mRS), Uplo, X, incX, Ap);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, Ap.getID(mRS), incX, 0, 0, 0);
     }
-    void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         // same as SYR2
         int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+    public void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
         // same as SPR2
         int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, Ap.getID(mRS), incX, incY, 0, 0);
     }
-    void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+    public void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
         // HEMV is the same as SYR2 validation-wise
         int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+    public void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
         // HBMV is the same as SYR2 validation-wise
         int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
         if (K < 0) {
@@ -900,40 +940,40 @@
         }
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+    public void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
         // HPMV is the same as SPR2
         int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, Ap.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
     }
-    void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         // same as GERU
         validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
         int M = A.getType().getY();
         int N = A.getType().getX();
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+    public void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
         // same as SYR
-        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
+        int N = validateSYR(Element.F64_2(mRS), Uplo, X, incX, A);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, A.getID(mRS), incX, 0, 0, 0);
     }
-    void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+    public void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
         // equivalent to SPR for validation
         int N = validateSPR(Element.F64_2(mRS), Uplo, X, incX, Ap);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, Ap.getID(mRS), incX, 0, 0, 0);
     }
-    void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+    public void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
         // same as SYR2
         int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
     }
-    void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+    public void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
         // same as SPR2
         int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, Ap.getID(mRS), incX, incY, 0, 0);
@@ -945,56 +985,74 @@
      */
 
     static void validateL3(Element e, int TransA, int TransB, int Side, Allocation A, Allocation B, Allocation C) {
-        int aX = -1, aY = -1, bX = -1, bY = -1, cX = -1, cY = -1;
+        int aM = -1, aN = -1, bM = -1, bN = -1, cM = -1, cN = -1;
         if ((A != null && !A.getType().getElement().isCompatible(e)) ||
             (B != null && !B.getType().getElement().isCompatible(e)) ||
             (C != null && !C.getType().getElement().isCompatible(e))) {
             throw new RSRuntimeException("Called BLAS with wrong Element type");
         }
-        if (C != null) {
-            cX = C.getType().getY();
-            cY = C.getType().getX();
+        if (C == null) {
+            //since matrix C is used to store the result, it cannot be null.
+            throw new RSRuntimeException("Allocation C cannot be null");
         }
+        cM = C.getType().getY();
+        cN = C.getType().getX();
+
         if (Side == RIGHT) {
+            if ((A == null && B != null) || (A != null && B == null)) {
+                throw new RSRuntimeException("Provided Matrix A without Matrix B, or vice versa");
+            }
             if (B != null) {
-                bX = A.getType().getY();
-                bY = A.getType().getX();
+                bM = A.getType().getY();
+                bN = A.getType().getX();
             }
             if (A != null) {
-                aX = B.getType().getY();
-                aY = B.getType().getX();
+                aM = B.getType().getY();
+                aN = B.getType().getX();
             }
         } else {
             if (A != null) {
-                if (TransA == TRANSPOSE) {
-                    aY = A.getType().getY();
-                    aX = A.getType().getX();
+                if (TransA == TRANSPOSE || TransA == CONJ_TRANSPOSE) {
+                    aN = A.getType().getY();
+                    aM = A.getType().getX();
                 } else {
-                    aX = A.getType().getY();
-                    aY = A.getType().getX();
+                    aM = A.getType().getY();
+                    aN = A.getType().getX();
                 }
             }
             if (B != null) {
-                if (TransB == TRANSPOSE) {
-                    bY = B.getType().getY();
-                    bX = B.getType().getX();
+                if (TransB == TRANSPOSE || TransB == CONJ_TRANSPOSE) {
+                    bN = B.getType().getY();
+                    bM = B.getType().getX();
                 } else {
-                    bX = B.getType().getY();
-                    bY = B.getType().getX();
+                    bM = B.getType().getY();
+                    bN = B.getType().getX();
                 }
             }
         }
         if (A != null && B != null && C != null) {
-            if (aY != bX || aX != cX || bY != cY) {
+            if (aN != bM || aM != cM || bN != cN) {
                 throw new RSRuntimeException("Called BLAS with invalid dimensions");
             }
         } else if (A != null && C != null) {
-            // A and C only
-            if (aX != cY || aY != cX) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            // A and C only, for SYRK
+            if (cM != cN) {
+                throw new RSRuntimeException("Matrix C is not symmetric");
+            }
+            if (TransA != NO_TRANSPOSE) {
+                if (aN != cM) {
+                    throw new RSRuntimeException("Called BLAS with invalid dimensions");
+                }
+            } else {
+                if (aM != cM) {
+                    throw new RSRuntimeException("Called BLAS with invalid dimensions");
+                }
             }
         } else if (A != null && B != null) {
             // A and B only
+            if (aN != bM) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
         }
 
     }
@@ -1006,14 +1064,14 @@
         validateL3(Element.F32(mRS), TransA, TransB, 0, A, B, C);
 
         int M = -1, N = -1, K = -1;
-        if (TransA == TRANSPOSE) {
+        if (TransA != NO_TRANSPOSE) {
             M = A.getType().getX();
             K = A.getType().getY();
         } else {
             M = A.getType().getY();
             K = A.getType().getX();
         }
-        if (TransB == TRANSPOSE) {
+        if (TransB != NO_TRANSPOSE) {
             N = B.getType().getY();
         } else {
             N = B.getType().getX();
@@ -1027,14 +1085,14 @@
         validateTranspose(TransB);
         validateL3(Element.F64(mRS), TransA, TransB, 0, A, B, C);
         int M = -1, N = -1, K = -1;
-        if (TransA == TRANSPOSE) {
+        if (TransA != NO_TRANSPOSE) {
             M = A.getType().getX();
             K = A.getType().getY();
         } else {
             M = A.getType().getY();
             K = A.getType().getX();
         }
-        if (TransB == TRANSPOSE) {
+        if (TransB != NO_TRANSPOSE) {
             N = B.getType().getY();
         } else {
             N = B.getType().getX();
@@ -1048,14 +1106,14 @@
         validateTranspose(TransB);
         validateL3(Element.F32_2(mRS), TransA, TransB, 0, A, B, C);
         int M = -1, N = -1, K = -1;
-        if (TransA == TRANSPOSE) {
+        if (TransA != NO_TRANSPOSE) {
             M = A.getType().getX();
             K = A.getType().getY();
         } else {
             M = A.getType().getY();
             K = A.getType().getX();
         }
-        if (TransB == TRANSPOSE) {
+        if (TransB != NO_TRANSPOSE) {
             N = B.getType().getY();
         } else {
             N = B.getType().getX();
@@ -1070,14 +1128,14 @@
         validateTranspose(TransB);
         validateL3(Element.F64_2(mRS), TransA, TransB, 0, A, B, C);
         int M = -1, N = -1, K = -1;
-        if (TransA == TRANSPOSE) {
+        if (TransA != NO_TRANSPOSE) {
             M = A.getType().getX();
             K = A.getType().getY();
         } else {
             M = A.getType().getY();
             K = A.getType().getX();
         }
-        if (TransB == TRANSPOSE) {
+        if (TransB != NO_TRANSPOSE) {
             N = B.getType().getY();
         } else {
             N = B.getType().getX();
@@ -1090,6 +1148,10 @@
                       Allocation B, float beta, Allocation C) {
         validateSide(Side);
         validateUplo(Uplo);
+        //For SYMM, Matrix A should be symmetric
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
         validateL3(Element.F32(mRS), 0, 0, Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, A.getID(mRS), B.getID(mRS),
                                         beta, C.getID(mRS), 0, 0, 0, 0);
@@ -1098,6 +1160,9 @@
                       Allocation B, double beta, Allocation C) {
         validateSide(Side);
         validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
         validateL3(Element.F64(mRS), 0, 0, Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, A.getID(mRS), B.getID(mRS),
                                         beta, C.getID(mRS), 0, 0, 0, 0);
@@ -1106,6 +1171,9 @@
                       Allocation B, Float2 beta, Allocation C) {
         validateSide(Side);
         validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
         validateL3(Element.F32_2(mRS), 0, 0, Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
                                          beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
@@ -1114,6 +1182,9 @@
                       Allocation B, Double2 beta, Allocation C) {
         validateSide(Side);
         validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
         validateL3(Element.F64_2(mRS), 0, 0, Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
                                    beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
@@ -1124,7 +1195,7 @@
         validateUplo(Uplo);
         validateL3(Element.F32(mRS), Trans, 0, 0, A, null, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
@@ -1138,37 +1209,37 @@
         validateUplo(Uplo);
         validateL3(Element.F64(mRS), Trans, 0, 0, A, null, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
         mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), 0, beta, C.getID(mRS), 0, 0, 0, 0);
     }
-    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, float alphaX, float alphaY, Allocation A, float betaX, float betaY, Allocation C) {
+    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Float2 beta, Allocation C) {
         validateTranspose(Trans);
         validateUplo(Uplo);
         validateL3(Element.F32_2(mRS), Trans, 0, 0, A, null, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alphaX, alphaY, A.getID(mRS), 0, betaX, betaY,
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), 0, beta.x, beta.y,
                                          C.getID(mRS), 0, 0, 0, 0);
     }
-    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, double alphaX, double alphaY, Allocation A, double betaX, double betaY, Allocation C) {
+    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Double2 beta, Allocation C) {
         validateTranspose(Trans);
         validateUplo(Uplo);
         validateL3(Element.F64_2(mRS), Trans, 0, 0, A, null, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alphaX, alphaY, A.getID(mRS), 0, betaX, betaY,
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), 0, beta.x, beta.y,
                                    C.getID(mRS), 0, 0, 0, 0);
     }
 
@@ -1189,7 +1260,7 @@
             // check rows versus C
             Cdim = A.getType().getY();
         }
-        if (C.getType().getX() != Cdim && C.getType().getY() != Cdim) {
+        if (C.getType().getX() != Cdim || C.getType().getY() != Cdim) {
             throw new RSRuntimeException("Invalid symmetric matrix in SYR2K");
         }
         // A dims == B dims
@@ -1201,7 +1272,7 @@
         validateUplo(Uplo);
         validateSYR2K(Element.F32(mRS), Trans, A, B, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
@@ -1212,59 +1283,59 @@
         validateUplo(Uplo);
         validateSYR2K(Element.F64(mRS), Trans, A, B, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
     }
     public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
         validateUplo(Uplo);
         validateSYR2K(Element.F32_2(mRS), Trans, A, B, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
     }
     public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
         validateUplo(Uplo);
         validateSYR2K(Element.F64_2(mRS), Trans, A, B, C);
         int K = -1;
-        if (Trans == TRANSPOSE) {
+        if (Trans != NO_TRANSPOSE) {
             K = A.getType().getY();
         } else {
             K = A.getType().getX();
         }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
     }
 
     static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
         validateSide(Side);
         validateTranspose(TransA);
-        int aX = -1, aY = -1, bX = -1, bY = -1;
+        int aM = -1, aN = -1, bM = -1, bN = -1;
         if (!A.getType().getElement().isCompatible(e) ||
             !B.getType().getElement().isCompatible(e)) {
             throw new RSRuntimeException("Called BLAS with wrong Element type");
         }
-        if (TransA == TRANSPOSE) {
-            aY = A.getType().getY();
-            aX = A.getType().getX();
-        } else {
-            aY = A.getType().getX();
-            aX = A.getType().getY();
+
+        aM = A.getType().getY();
+        aN = A.getType().getX();
+        if (aM != aN) {
+            throw new RSRuntimeException("Called TRMM with a non-symmetric matrix A");
         }
-        bX = B.getType().getY();
-        bY = B.getType().getX();
+
+        bM = B.getType().getY();
+        bN = B.getType().getX();
         if (Side == LEFT) {
-            if (aX == 0 || aY != bX) {
+            if (aN != bM) {
                 throw new RSRuntimeException("Called TRMM with invalid matrices");
             }
         } else {
-            if (bY != aX || aY == 0) {
+            if (bN != aM) {
                 throw new RSRuntimeException("Called TRMM with invalid matrices");
             }
         }
@@ -1280,26 +1351,26 @@
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRMM(Element.F64(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, A.getID(mRS), B.getID(mRS), 0.f, 0, 0, 0, 0, 0);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
     }
     public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
                                          alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
     }
     public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
                                    alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
     }
 
     static void validateTRSM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
-        int adim = -1, bX = -1, bY = -1;
+        int adim = -1, bM = -1, bN = -1;
         validateSide(Side);
         validateTranspose(TransA);
         if (!A.getType().getElement().isCompatible(e) ||
@@ -1313,16 +1384,16 @@
             // for now we assume adapters are sufficient, will reevaluate in the future
             throw new RSRuntimeException("Called TRSM with a non-symmetric matrix A");
         }
-        bX = B.getType().getY();
-        bY = B.getType().getX();
+        bM = B.getType().getY();
+        bN = B.getType().getX();
         if (Side == LEFT) {
             // A is M*M
-            if (adim != bY) {
+            if (adim != bM) {
                 throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
             }
         } else {
             // A is N*N
-            if (adim != bX) {
+            if (adim != bN) {
                 throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
             }
         }
@@ -1338,21 +1409,21 @@
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRSM(Element.F64(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
                                         alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
     }
     public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
                                          alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
     }
     public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
         validateUplo(Uplo);
         validateDiag(Diag);
         validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
                                    alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
     }
 
@@ -1379,17 +1450,17 @@
             throw new RSRuntimeException("Called HEMM with mismatched B and C");
         }
     }
-    public void CHEMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
+    public void CHEMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
         validateUplo(Uplo);
         validateHEMM(Element.F32_2(mRS), Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                         alpha, 0, A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+                                         alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
     }
-    public void ZHEMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
+    public void ZHEMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
         validateUplo(Uplo);
-        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
+        validateHEMM(Element.F64_2(mRS), Side, A, B, C);
         mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                   alpha, 0, A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+                                   alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
     }
 
     static void validateHERK(Element e, @Transpose int Trans, Allocation A, Allocation C) {
@@ -1403,11 +1474,11 @@
             throw new RSRuntimeException("Called HERK with non-square C");
         }
         if (Trans == NO_TRANSPOSE) {
-            if (cdim != A.getType().getX()) {
+            if (cdim != A.getType().getY()) {
                 throw new RSRuntimeException("Called HERK with invalid A");
             }
         } else {
-            if (cdim != A.getType().getY()) {
+            if (cdim != A.getType().getX()) {
                 throw new RSRuntimeException("Called HERK with invalid A");
             }
         }
@@ -1416,7 +1487,7 @@
         validateUplo(Uplo);
         validateHERK(Element.F32_2(mRS), Trans, A, C);
         int k = 0;
-        if (Trans == TRANSPOSE) {
+        if (Trans == CONJ_TRANSPOSE) {
             k = A.getType().getY();
         } else {
             k = A.getType().getX();
@@ -1428,7 +1499,7 @@
         validateUplo(Uplo);
         validateHERK(Element.F64_2(mRS), Trans, A, C);
         int k = 0;
-        if (Trans == TRANSPOSE) {
+        if (Trans == CONJ_TRANSPOSE) {
             k = A.getType().getY();
         } else {
             k = A.getType().getX();
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index cbe87fc..5ef807d 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -526,7 +526,7 @@
     call.alpha.c.r = alphaX;
     call.alpha.c.i = alphaY;
     call.beta.c.r = betaX;
-    call.beta.c.r = betaY;
+    call.beta.c.i = betaY;
     call.incX = incX;
     call.incY = incY;
     call.KL = KL;
@@ -561,7 +561,7 @@
     call.alpha.z.r = alphaX;
     call.alpha.z.i = alphaY;
     call.beta.z.r = betaX;
-    call.beta.z.r = betaY;
+    call.beta.z.i = betaY;
     call.incX = incX;
     call.incY = incY;
     call.KL = KL;
@@ -1102,9 +1102,8 @@
 nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
                             jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1119,9 +1118,8 @@
 nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
                                         jint mip, jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1136,9 +1134,8 @@
 nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
                                 jobject jbitmap, jint usage)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
@@ -1152,9 +1149,8 @@
 static void
 nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
     int w = bitmap.width();
     int h = bitmap.height();
 
@@ -1169,9 +1165,8 @@
 static void
 nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            GraphicsJNI::getSkBitmap(_env, jbitmap);
-    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
 
     bitmap.lockPixels();
     void* ptr = bitmap.getPixels();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 82a77d2..860939c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2060,7 +2060,9 @@
             UserState userState = getUserStateLocked(mUserId);
             if (!mIsAutomation) {
                 if (mService == null && mContext.bindServiceAsUser(
-                        mIntent, this, Context.BIND_AUTO_CREATE, new UserHandle(mUserId))) {
+                        mIntent, this,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                        new UserHandle(mUserId))) {
                     userState.mBindingServices.add(mComponentName);
                 }
             } else {
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 38827d0..d0b5898 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -41,12 +41,18 @@
              0,      0,      0, 1
     };
 
-    /** Matrix and offset used for value-only display inversion. */
+    /**
+     * Matrix and offset used for luminance inversion. Represents a transform
+     * from RGB to YIQ color space, rotation around the Y axis by 180 degrees,
+     * transform back to RGB color space, and subtraction from 1. The last row
+     * represents a non-multiplied addition, see surfaceflinger's ProgramCache
+     * for full implementation details.
+     */
     private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
-           0, -.5f, -.5f, 0,
-        -.5f,    0, -.5f, 0,
-        -.5f, -.5f,    0, 0,
-           1,    1,    1, 1
+        0.402f, -0.598f, -0.599f, 0,
+       -1.174f, -0.174f, -1.175f, 0,
+       -0.228f, -0.228f,  0.772f, 0,
+             1,       1,       1, 1
     };
 
     /** Default inversion mode for display color correction. */
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f42aef1..17c7e0c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1492,7 +1492,8 @@
         // RemoteViewsService.
         final long token = Binder.clearCallingIdentity();
         try {
-            mContext.bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE,
+            mContext.bindServiceAsUser(intent, conn,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     widget.provider.info.getProfile());
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -2907,7 +2908,8 @@
             UserHandle userHandle) {
         final long token = Binder.clearCallingIdentity();
         try {
-            mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
+            mContext.bindServiceAsUser(intent, connection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     userHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0e3867d..745c1906 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -461,7 +461,7 @@
     // to run during this time are placed in mPendingWhileIdleAlarms
     Alarm mPendingIdleUntil = null;
     Alarm mNextWakeFromIdle = null;
-    final ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
+    ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
 
     public AlarmManagerService(Context context) {
         super(context);
@@ -567,10 +567,14 @@
 
     void restorePendingWhileIdleAlarmsLocked() {
         // Bring pending alarms back into the main list.
-        final long nowElapsed = SystemClock.elapsedRealtime();
-        for (int i=mPendingWhileIdleAlarms.size() - 1; i >= 0 && mPendingIdleUntil == null; i--) {
-            Alarm a = mPendingWhileIdleAlarms.remove(i);
-            reAddAlarmLocked(a, nowElapsed, false);
+        if (mPendingWhileIdleAlarms.size() > 0) {
+            ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
+            mPendingWhileIdleAlarms = new ArrayList<>();
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            for (int i=alarms.size() - 1; i >= 0; i--) {
+                Alarm a = alarms.get(i);
+                reAddAlarmLocked(a, nowElapsed, false);
+            }
         }
 
         // Reschedule everything.
@@ -1053,11 +1057,16 @@
                     dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC, sdf);
                 }
             }
-            if (mPendingIdleUntil != null) {
+            if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) {
                 pw.println();
                 pw.println("Idle mode state:");
-                pw.print("  Idling until: "); pw.println(mPendingIdleUntil);
-                mPendingIdleUntil.dump(pw, "    ", nowRTC, nowELAPSED, sdf);
+                pw.print("  Idling until: ");
+                if (mPendingIdleUntil != null) {
+                    pw.println(mPendingIdleUntil);
+                    mPendingIdleUntil.dump(pw, "    ", nowRTC, nowELAPSED, sdf);
+                } else {
+                    pw.println("null");
+                }
                 pw.println("  Pending alarms:");
                 dumpAlarmList(pw, mPendingWhileIdleAlarms, "    ", nowELAPSED, nowRTC, sdf);
             }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ef82bb7..1019faa 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -48,6 +48,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -443,6 +444,16 @@
     /** Internal death rec list */
     Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
 
+    @Override
+    public boolean isBleScanAlwaysAvailable() {
+        try {
+            return (Settings.Global.getInt(mContentResolver,
+                    Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
+        } catch (SettingNotFoundException e) {
+        }
+        return false;
+    }
+
     public int updateBleAppCount(IBinder token, boolean enable) {
         if (enable) {
             ClientDeathRecipient r = mBleApps.get(token);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 12a99b0..1a75b8a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -24,6 +24,7 @@
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
 import android.annotation.Nullable;
@@ -832,7 +833,8 @@
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
         }
 
-        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
+        if ((uidRules & RULE_REJECT_ALL) != 0
+                || (networkCostly && (uidRules & RULE_REJECT_METERED) != 0)) {
             return true;
         }
 
@@ -3490,7 +3492,7 @@
             synchronized(mRulesLock) {
                 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             }
-            if ((uidRules & RULE_REJECT_METERED) != 0) {
+            if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
                 // we could silently fail or we can filter the available nets to only give
                 // them those they have access to.  Chose the more useful
                 networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
new file mode 100644
index 0000000..b7bc0f0
--- /dev/null
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+import android.hardware.display.DisplayManager;
+import android.net.INetworkPolicyManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.IDeviceIdleController;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+import android.view.Display;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.am.BatteryStatsService;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Keeps track of device idleness and drives low power mode based on that.
+ */
+public class DeviceIdleController extends SystemService {
+    private static final String TAG = "DeviceIdleController";
+
+    public static final String SERVICE_NAME = "deviceidle";
+
+    private static final String ACTION_STEP_IDLE_STATE =
+            "com.android.server.device_idle.STEP_IDLE_STATE";
+
+    // TODO: These need to be moved to system settings.
+
+    /**
+     * This is the time, after becoming inactive, at which we start looking at the
+     * motion sensor to determine if the device is being left alone.  We don't do this
+     * immediately after going inactive just because we don't want to be continually running
+     * the significant motion sensor whenever the screen is off.
+     */
+    private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
+    /**
+     * This is the time, after seeing motion, that we wait after becoming inactive from
+     * that until we start looking for motion again.
+     */
+    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L;
+    /**
+     * This is the time, after the inactive timeout elapses, that we will wait looking
+     * for significant motion until we truly consider the device to be idle.
+     */
+    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = 30*60*1000L;
+    /**
+     * This is the initial time, after being idle, that we will allow ourself to be back
+     * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
+     */
+    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
+    /**
+     * Maximum pending idle timeout (time spent running) we will be allowed to use.
+     */
+    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
+    /**
+     * Scaling factor to apply to current pending idle timeout each time we cycle through
+     * that state.
+     */
+    private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
+    /**
+     * This is the initial time that we want to sit in the idle state before waking up
+     * again to return to pending idle and allowing normal work to run.
+     */
+    private static final long DEFAULT_IDLE_TIMEOUT = 60*60*1000L;
+    /**
+     * Maximum idle duration we will be allowed to use.
+     */
+    private static final long DEFAULT_MAX_IDLE_TIMEOUT = 6*60*60*1000L;
+    /**
+     * Scaling factor to apply to current idle timeout each time we cycle through that state.
+     */
+    private static final float DEFAULT_IDLE_FACTOR = 2f;
+    /**
+     * This is the minimum time we will allow until the next upcoming alarm for us to
+     * actually go in to idle mode.
+     */
+    private static final long DEFAULT_MIN_TIME_TO_ALARM = 60*60*1000L;
+
+    private AlarmManager mAlarmManager;
+    private IBatteryStats mBatteryStats;
+    private PowerManagerInternal mLocalPowerManager;
+    private INetworkPolicyManager mNetworkPolicyManager;
+    private DisplayManager mDisplayManager;
+    private SensorManager mSensorManager;
+    private Sensor mSigMotionSensor;
+    private PendingIntent mAlarmIntent;
+    private Intent mIdleIntent;
+    private Display mCurDisplay;
+    private boolean mScreenOn;
+    private boolean mCharging;
+    private boolean mSigMotionActive;
+
+    /** Device is currently active. */
+    private static final int STATE_ACTIVE = 0;
+    /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
+    private static final int STATE_INACTIVE = 1;
+    /** Device is past the initial inactive period, and waiting for the next idle period. */
+    private static final int STATE_IDLE_PENDING = 2;
+    /** Device is in the idle state, trying to stay asleep as much as possible. */
+    private static final int STATE_IDLE = 3;
+    /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
+    private static final int STATE_IDLE_MAINTENANCE = 4;
+    private static String stateToString(int state) {
+        switch (state) {
+            case STATE_ACTIVE: return "ACTIVE";
+            case STATE_INACTIVE: return "INACTIVE";
+            case STATE_IDLE_PENDING: return "IDLE_PENDING";
+            case STATE_IDLE: return "IDLE";
+            case STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
+            default: return Integer.toString(state);
+        }
+    }
+
+    private int mState;
+
+    private long mInactiveTimeout;
+    private long mNextAlarmTime;
+    private long mNextIdlePendingDelay;
+    private long mNextIdleDelay;
+
+    public final AtomicFile mConfigFile;
+
+    /**
+     * Package names the system has white-listed to opt out of power save restrictions.
+     */
+    private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();
+
+    /**
+     * Package names the user has white-listed to opt out of power save restrictions.
+     */
+    private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();
+
+    /**
+     * UIDs that have been white-listed to opt out of power save restrictions.
+     */
+    private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
+
+    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("plugged", 0);
+                updateChargingLocked(plugged != 0);
+            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
+                synchronized (DeviceIdleController.this) {
+                    stepIdleStateLocked();
+                }
+            }
+        }
+    };
+
+    private final DisplayManager.DisplayListener mDisplayListener
+            = new DisplayManager.DisplayListener() {
+        @Override public void onDisplayAdded(int displayId) {
+        }
+
+        @Override public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override public void onDisplayChanged(int displayId) {
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                synchronized (DeviceIdleController.this) {
+                    updateDisplayLocked();
+                }
+            }
+        }
+    };
+
+    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
+        @Override public void onTrigger(TriggerEvent event) {
+            synchronized (DeviceIdleController.this) {
+                significantMotionLocked();
+            }
+        }
+    };
+
+    static final int MSG_WRITE_CONFIG = 1;
+    static final int MSG_REPORT_IDLE_ON = 2;
+    static final int MSG_REPORT_IDLE_OFF = 3;
+    static final int MSG_REPORT_ACTIVE = 4;
+
+    final class MyHandler extends Handler {
+        MyHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_WRITE_CONFIG: {
+                    handleWriteConfigFile();
+                } break;
+                case MSG_REPORT_IDLE_ON: {
+                    mLocalPowerManager.setDeviceIdleMode(true);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(true);
+                        mBatteryStats.noteDeviceIdleMode(true, false, false);
+                    } catch (RemoteException e) {
+                    }
+                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                } break;
+                case MSG_REPORT_IDLE_OFF: {
+                    mLocalPowerManager.setDeviceIdleMode(false);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(false);
+                        mBatteryStats.noteDeviceIdleMode(false, false, false);
+                    } catch (RemoteException e) {
+                    }
+                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                } break;
+                case MSG_REPORT_ACTIVE: {
+                    boolean fromMotion = msg.arg1 != 0;
+                    boolean needBroadcast = msg.arg2 != 0;
+                    mLocalPowerManager.setDeviceIdleMode(false);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(false);
+                        mBatteryStats.noteDeviceIdleMode(false, !fromMotion, fromMotion);
+                    } catch (RemoteException e) {
+                    }
+                    if (needBroadcast) {
+                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                    }
+                } break;
+            }
+        }
+    }
+
+    final MyHandler mHandler;
+
+    private final class BinderService extends IDeviceIdleController.Stub {
+        @Override public void addPowerSaveWhitelistApp(String name) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            addPowerSaveWhitelistAppInternal(name);
+        }
+
+        @Override public void removePowerSaveWhitelistApp(String name) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            removePowerSaveWhitelistAppInternal(name);
+        }
+
+        @Override public String[] getSystemPowerWhitelist() {
+            return getSystemPowerWhitelistInternal();
+        }
+
+        @Override public String[] getFullPowerWhitelist() {
+            return getFullPowerWhitelistInternal();
+        }
+
+        @Override public int[] getAppIdWhitelist() {
+            return getAppIdWhitelistInternal();
+        }
+
+        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            DeviceIdleController.this.dump(fd, pw, args);
+        }
+    }
+
+    public DeviceIdleController(Context context) {
+        super(context);
+        mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
+        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
+    }
+
+    private static File getSystemDir() {
+        return new File(Environment.getDataDirectory(), "system");
+    }
+
+    @Override
+    public void onStart() {
+        final PackageManager pm = getContext().getPackageManager();
+
+        synchronized (this) {
+            SystemConfig sysConfig = SystemConfig.getInstance();
+            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
+            for (int i=0; i<allowPower.size(); i++) {
+                String pkg = allowPower.valueAt(i);
+                try {
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        mPowerSaveWhitelistApps.put(ai.packageName,
+                                UserHandle.getAppId(ai.uid));
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+
+            readConfigFileLocked();
+            updateWhitelistAppIdsLocked();
+
+            mScreenOn = true;
+            // Start out assuming we are charging.  If we aren't, we will at least get
+            // a battery update the next time the level drops.
+            mCharging = true;
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+        }
+
+        publishBinderService(SERVICE_NAME, new BinderService());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            synchronized (this) {
+                mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+                mBatteryStats = BatteryStatsService.getService();
+                mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+                mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
+                                    ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+                mDisplayManager = (DisplayManager) getContext().getSystemService(
+                        Context.DISPLAY_SERVICE);
+                mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+                mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
+
+                Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
+                        .setPackage("android")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+
+                mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+                IntentFilter filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+                filter.addAction(ACTION_STEP_IDLE_STATE);
+                getContext().registerReceiver(mReceiver, filter);
+
+                mDisplayManager.registerDisplayListener(mDisplayListener, null);
+                updateDisplayLocked();
+            }
+        }
+    }
+
+    public boolean addPowerSaveWhitelistAppInternal(String name) {
+        synchronized (this) {
+            try {
+                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, 0);
+                if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
+                    reportPowerSaveWhitelistChangedLocked();
+                    updateWhitelistAppIdsLocked();
+                    writeConfigFileLocked();
+                }
+                return true;
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+        }
+    }
+
+    public boolean removePowerSaveWhitelistAppInternal(String name) {
+        synchronized (this) {
+            if (mPowerSaveWhitelistUserApps.remove(name) != null) {
+                reportPowerSaveWhitelistChangedLocked();
+                updateWhitelistAppIdsLocked();
+                writeConfigFileLocked();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String[] getSystemPowerWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size();
+            String[] apps = new String[size];
+            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
+                apps[i] = mPowerSaveWhitelistApps.keyAt(i);
+            }
+            return apps;
+        }
+    }
+
+    public String[] getFullPowerWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
+            String[] apps = new String[size];
+            int cur = 0;
+            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
+                apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
+                cur++;
+            }
+            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
+                apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
+                cur++;
+            }
+            return apps;
+        }
+    }
+
+    public int[] getAppIdWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistAppIds.size();
+            int[] appids = new int[size];
+            for (int i = 0; i < size; i++) {
+                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+            }
+            return appids;
+        }
+    }
+
+    void updateDisplayLocked() {
+        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        // We consider any situation where the display is showing something to be it on,
+        // because if there is anything shown we are going to be updating it at some
+        // frequency so can't be allowed to go into deep sleeps.
+        boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
+        if (!screenOn && mScreenOn) {
+            mScreenOn = false;
+            becomeInactiveIfAppropriateLocked();
+        } else if (screenOn) {
+            mScreenOn = true;
+            becomeActiveLocked("screen");
+        }
+    }
+
+    void updateChargingLocked(boolean charging) {
+        if (!charging && mCharging) {
+            mCharging = false;
+            becomeInactiveIfAppropriateLocked();
+        } else if (charging) {
+            mCharging = charging;
+            becomeActiveLocked("charging");
+        }
+    }
+
+    void scheduleReportActiveLocked(boolean fromMotion) {
+        Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, fromMotion ? 1 : 0,
+                mState == STATE_IDLE ? 1 : 0);
+        mHandler.sendMessage(msg);
+    }
+
+    void becomeActiveLocked(String reason) {
+        if (mState != STATE_ACTIVE) {
+            EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
+            scheduleReportActiveLocked(false);
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+            mNextIdlePendingDelay = 0;
+            mNextIdleDelay = 0;
+            cancelAlarmLocked();
+            stopMonitoringSignificantMotion();
+        }
+    }
+
+    void becomeInactiveIfAppropriateLocked() {
+        if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
+            // Screen has turned off; we are now going to become inactive and start
+            // waiting to see if we will ultimately go idle.
+            mState = STATE_INACTIVE;
+            mNextIdlePendingDelay = 0;
+            mNextIdleDelay = 0;
+            scheduleAlarmLocked(mInactiveTimeout, false);
+            EventLogTags.writeDeviceIdle(mState, "no activity");
+        }
+    }
+
+    void stepIdleStateLocked() {
+        EventLogTags.writeDeviceIdleStep();
+
+        final long now = SystemClock.elapsedRealtime();
+        if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
+            if (mState != STATE_ACTIVE) {
+                becomeActiveLocked("alarm");
+            }
+            return;
+        }
+
+        switch (mState) {
+            case STATE_INACTIVE:
+                // We have now been inactive long enough, it is time to start looking
+                // for significant motion and sleep some more while doing so.
+                startMonitoringSignificantMotion();
+                scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
+                // Reset the upcoming idle delays.
+                mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
+                mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
+                mState = STATE_IDLE_PENDING;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                break;
+            case STATE_IDLE_PENDING:
+            case STATE_IDLE_MAINTENANCE:
+                // We have been waiting to become idle, and now it is time!  This is the
+                // only case where we want to use a wakeup alarm, because we do want to
+                // drag the device out of its sleep state in this case to do the next
+                // scheduled work.
+                scheduleAlarmLocked(mNextIdleDelay, true);
+                mNextIdleDelay = (long)(mNextIdleDelay*DEFAULT_IDLE_FACTOR);
+                if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
+                    mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
+                }
+                mState = STATE_IDLE;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
+                break;
+            case STATE_IDLE:
+                // We have been idling long enough, now it is time to do some work.
+                scheduleAlarmLocked(mNextIdlePendingDelay, false);
+                mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
+                if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
+                    mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
+                }
+                mState = STATE_IDLE_MAINTENANCE;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
+                break;
+        }
+    }
+
+    void significantMotionLocked() {
+        // When the sensor goes off, its trigger is automatically removed.
+        mSigMotionActive = false;
+        // The device is not yet active, so we want to go back to the pending idle
+        // state to wait again for no motion.  Note that we only monitor for significant
+        // motion after moving out of the inactive state, so no need to worry about that.
+        if (mState != STATE_ACTIVE) {
+            scheduleReportActiveLocked(true);
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+            EventLogTags.writeDeviceIdle(mState, "motion");
+            becomeInactiveIfAppropriateLocked();
+        }
+    }
+
+    void startMonitoringSignificantMotion() {
+        if (mSigMotionSensor != null && !mSigMotionActive) {
+            mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
+            mSigMotionActive = true;
+        }
+    }
+
+    void stopMonitoringSignificantMotion() {
+        if (mSigMotionActive) {
+            mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
+            mSigMotionActive = false;
+        }
+    }
+
+    void cancelAlarmLocked() {
+        if (mNextAlarmTime != 0) {
+            mNextAlarmTime = 0;
+            mAlarmManager.cancel(mAlarmIntent);
+        }
+    }
+
+    void scheduleAlarmLocked(long delay, boolean idleUntil) {
+        if (mSigMotionSensor == null) {
+            // If there is no significant motion sensor on this device, then we won't schedule
+            // alarms, because we can't determine if the device is not moving.  This effectively
+            // turns off normal exeuction of device idling, although it is still possible to
+            // manually poke it by pretending like the alarm is going off.
+            return;
+        }
+        mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
+        if (idleUntil) {
+            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        } else {
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        }
+    }
+
+    private void updateWhitelistAppIdsLocked() {
+        mPowerSaveWhitelistAppIds.clear();
+        for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) {
+            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
+        }
+        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
+            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
+        }
+    }
+
+    private void reportPowerSaveWhitelistChangedLocked() {
+        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        getContext().sendBroadcast(intent);
+    }
+
+    void readConfigFileLocked() {
+        Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
+        mPowerSaveWhitelistUserApps.clear();
+        FileInputStream stream;
+        try {
+            stream = mConfigFile.openRead();
+        } catch (FileNotFoundException e) {
+            return;
+        }
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+            readConfigFileLocked(parser);
+        } catch (XmlPullParserException e) {
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException e) {
+            }
+        }
+
+    }
+
+    private void readConfigFileLocked(XmlPullParser parser) {
+        final PackageManager pm = getContext().getPackageManager();
+
+        try {
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("wl")) {
+                    String name = parser.getAttributeValue(null, "n");
+                    if (name != null) {
+                        try {
+                            ApplicationInfo ai = pm.getApplicationInfo(name, 0);
+                            mPowerSaveWhitelistUserApps.put(ai.packageName,
+                                    UserHandle.getAppId(ai.uid));
+                        } catch (PackageManager.NameNotFoundException e) {
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Unknown element under <config>: "
+                            + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+
+        } catch (IllegalStateException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        }
+    }
+
+    void writeConfigFileLocked() {
+        mHandler.removeMessages(MSG_WRITE_CONFIG);
+        mHandler.sendEmptyMessageDelayed(MSG_WRITE_CONFIG, 5000);
+    }
+
+    void handleWriteConfigFile() {
+        final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
+
+        try {
+            synchronized (this) {
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(memStream, "utf-8");
+                writeConfigFileLocked(out);
+            }
+        } catch (IOException e) {
+        }
+
+        synchronized (mConfigFile) {
+            FileOutputStream stream = null;
+            try {
+                stream = mConfigFile.startWrite();
+                memStream.writeTo(stream);
+                stream.flush();
+                FileUtils.sync(stream);
+                stream.close();
+                mConfigFile.finishWrite(stream);
+            } catch (IOException e) {
+                Slog.w(TAG, "Error writing config file", e);
+                mConfigFile.failWrite(stream);
+            }
+        }
+    }
+
+    void writeConfigFileLocked(XmlSerializer out) throws IOException {
+        out.startDocument(null, true);
+        out.startTag(null, "config");
+        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
+            String name = mPowerSaveWhitelistUserApps.keyAt(i);
+            out.startTag(null, "wl");
+            out.attribute(null, "n", name);
+            out.endTag(null, "wl");
+        }
+        out.endTag(null, "config");
+        out.endDocument();
+    }
+
+    private void dumpHelp(PrintWriter pw) {
+        pw.println("Device idle controller (deviceidle) dump options:");
+        pw.println("  [-h] [CMD]");
+        pw.println("  -h: print this help text.");
+        pw.println("Commands:");
+        pw.println("  step");
+        pw.println("    Immediately step to next state, without waiting for alarm.");
+        pw.println("  whitelist");
+        pw.println("    Add (prefix with +) or remove (prefix with -) packages.");
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " without permission " + android.Manifest.permission.DUMP);
+            return;
+        }
+
+        if (args != null) {
+            for (int i=0; i<args.length; i++) {
+                String arg = args[i];
+                if ("-h".equals(arg)) {
+                    dumpHelp(pw);
+                    return;
+                } else if ("step".equals(arg)) {
+                    synchronized (this) {
+                        stepIdleStateLocked();
+                        pw.print("Stepped to: "); pw.println(stateToString(mState));
+                    }
+                    return;
+                } else if ("whitelist".equals(arg)) {
+                    i++;
+                    while (i < args.length) {
+                        arg = args[i];
+                        i++;
+                        if (arg.length() < 1 || (arg.charAt(0) != '-'
+                                && arg.charAt(0) != '+')) {
+                            pw.println("Package must be prefixed with + or -: " + arg);
+                            return;
+                        }
+                        char op = arg.charAt(0);
+                        String pkg = arg.substring(1);
+                        if (op == '+') {
+                            if (addPowerSaveWhitelistAppInternal(pkg)) {
+                                pw.println("Added: " + pkg);
+                            } else {
+                                pw.println("Unknown package: " + pkg);
+                            }
+                        } else {
+                            if (removePowerSaveWhitelistAppInternal(pkg)) {
+                                pw.println("Removed: " + pkg);
+                            }
+                        }
+                    }
+                    return;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+                    pw.println("Unknown option: " + arg);
+                    return;
+                } else {
+                    pw.println("Unknown command: " + arg);
+                    return;
+                }
+            }
+        }
+
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size();
+            if (size > 0) {
+                pw.println("  Whitelist system apps:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    ");
+                    pw.println(mPowerSaveWhitelistApps.keyAt(i));
+                }
+            }
+            size = mPowerSaveWhitelistUserApps.size();
+            if (size > 0) {
+                pw.println("  Whitelist user apps:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    ");
+                    pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
+                }
+            }
+            size = mPowerSaveWhitelistAppIds.size();
+            if (size > 0) {
+                pw.println("  Whitelist app uids:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    UID=");
+                    pw.print(mPowerSaveWhitelistAppIds.keyAt(i));
+                    pw.print(": ");
+                    pw.print(mPowerSaveWhitelistAppIds.valueAt(i));
+                    pw.println();
+                }
+            }
+            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
+            pw.print("  mCurDisplay="); pw.println(mCurDisplay);
+            pw.print("  mScreenOn="); pw.println(mScreenOn);
+            pw.print("  mCharging="); pw.println(mCharging);
+            pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
+            pw.print("  mState="); pw.println(stateToString(mState));
+            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
+            pw.println();
+            if (mNextAlarmTime != 0) {
+                pw.print("  mNextAlarmTime=");
+                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
+                pw.println();
+            }
+            if (mNextIdlePendingDelay != 0) {
+                pw.print("  mNextIdlePendingDelay=");
+                TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
+                pw.println();
+            }
+            if (mNextIdleDelay != 0) {
+                pw.print("  mNextIdleDelay=");
+                TimeUtils.formatDuration(mNextIdleDelay, pw);
+                pw.println();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index abd2ca0..ef9d0c3 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -180,6 +180,11 @@
 34001 device_idle_step
 34002 device_idle_wake_from_idle (is_idle|1|5), (reason|3)
 
+# ---------------------------
+# DisplayManagerService.java
+# ---------------------------
+# Auto-brightness adjustments by the user.
+35000 auto_brightness_adj (old_adj|5),(old_lux|5),(old_brightness|5),(old_gamma|5),(new_adj|5),(new_lux|5),(new_brightness|5),(new_gamma|5)
 
 # ---------------------------
 # ConnectivityService.java
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0f9090d..4fda370 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1993,7 +1993,8 @@
             if (mHaveConnection && !mVisibleBound) {
                 bindCurrentInputMethodService(
                         mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE
-                                | Context.BIND_TREAT_LIKE_ACTIVITY);
+                                | Context.BIND_TREAT_LIKE_ACTIVITY
+                                | Context.BIND_FOREGROUND_SERVICE);
                 mVisibleBound = true;
             }
             res = true;
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 7172ab7..0925fa5 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -62,11 +62,11 @@
 import android.os.storage.StorageResultCode;
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
-import android.util.DebugUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.Xml;
@@ -229,6 +229,7 @@
         public static final int VOLUME_FS_UUID_CHANGED = 653;
         public static final int VOLUME_FS_LABEL_CHANGED = 654;
         public static final int VOLUME_PATH_CHANGED = 655;
+        public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
         public static final int VOLUME_DESTROYED = 659;
 
         public static final int MOVE_STATUS = 660;
@@ -251,49 +252,7 @@
     private static final String ATTR_NICKNAME = "nickname";
     private static final String ATTR_USER_FLAGS = "userFlags";
 
-    private final AtomicFile mMetadataFile;
-
-    private static class VolumeMetadata {
-        public final int type;
-        public final String fsUuid;
-        public String nickname;
-        public int userFlags;
-
-        public VolumeMetadata(int type, String fsUuid) {
-            this.type = type;
-            this.fsUuid = Preconditions.checkNotNull(fsUuid);
-        }
-
-        public static VolumeMetadata read(XmlPullParser in) throws IOException {
-            final int type = readIntAttribute(in, ATTR_TYPE);
-            final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
-            final VolumeMetadata meta = new VolumeMetadata(type, fsUuid);
-            meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
-            meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
-            return meta;
-        }
-
-        public static void write(XmlSerializer out, VolumeMetadata meta) throws IOException {
-            out.startTag(null, TAG_VOLUME);
-            writeIntAttribute(out, ATTR_TYPE, meta.type);
-            writeStringAttribute(out, ATTR_FS_UUID, meta.fsUuid);
-            writeStringAttribute(out, ATTR_NICKNAME, meta.nickname);
-            writeIntAttribute(out, ATTR_USER_FLAGS, meta.userFlags);
-            out.endTag(null, TAG_VOLUME);
-        }
-
-        public void dump(IndentingPrintWriter pw) {
-            pw.println("VolumeMetadata:");
-            pw.increaseIndent();
-            pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type));
-            pw.printPair("fsUuid", fsUuid);
-            pw.printPair("nickname", nickname);
-            pw.printPair("userFlags",
-                    DebugUtils.flagsToString(VolumeInfo.class, "USER_FLAG_", userFlags));
-            pw.decreaseIndent();
-            pw.println();
-        }
-    }
+    private final AtomicFile mSettingsFile;
 
     /**
      * <em>Never</em> hold the lock while performing downcalls into vold, since
@@ -311,9 +270,9 @@
     @GuardedBy("mLock")
     private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
 
-    /** Map from UUID to metadata */
+    /** Map from UUID to record */
     @GuardedBy("mLock")
-    private ArrayMap<String, VolumeMetadata> mMetadata = new ArrayMap<>();
+    private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private String mPrimaryStorageUuid;
 
@@ -370,15 +329,6 @@
         }
     }
 
-    private VolumeMetadata findOrCreateMetadataLocked(VolumeInfo vol) {
-        VolumeMetadata meta = mMetadata.get(vol.fsUuid);
-        if (meta == null) {
-            meta = new VolumeMetadata(vol.type, vol.fsUuid);
-            mMetadata.put(meta.fsUuid, meta);
-        }
-        return meta;
-    }
-
     private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
         synchronized (mLock) {
             CountDownLatch latch = mDiskScanLatches.get(diskId);
@@ -580,7 +530,9 @@
                 case H_FSTRIM: {
                     if (!isReady()) {
                         Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
-                        sendMessageDelayed(obtainMessage(H_FSTRIM), DateUtils.SECOND_IN_MILLIS);
+                        sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
+                                DateUtils.SECOND_IN_MILLIS);
+                        break;
                     }
 
                     Slog.i(TAG, "Running fstrim idle maintenance");
@@ -710,6 +662,9 @@
 
             try {
                 mConnector.execute("volume", "reset");
+                for (int userId : mStartedUsers) {
+                    mConnector.execute("volume", "start_user", userId);
+                }
             } catch (NativeDaemonConnectorException e) {
                 Slog.w(TAG, "Failed to reset vold", e);
             }
@@ -911,7 +866,7 @@
                     final int oldState = vol.state;
                     final int newState = Integer.parseInt(cooked[2]);
                     vol.state = newState;
-                    onVolumeStateChangedLocked(vol.clone(), oldState, newState);
+                    onVolumeStateChangedLocked(vol, oldState, newState);
                 }
                 break;
             }
@@ -921,7 +876,6 @@
                 if (vol != null) {
                     vol.fsType = cooked[2];
                 }
-                mCallbacks.notifyVolumeMetadataChanged(vol.clone());
                 break;
             }
             case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
@@ -930,8 +884,6 @@
                 if (vol != null) {
                     vol.fsUuid = cooked[2];
                 }
-                refreshMetadataLocked();
-                mCallbacks.notifyVolumeMetadataChanged(vol.clone());
                 break;
             }
             case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
@@ -943,7 +895,7 @@
                     }
                     vol.fsLabel = builder.toString().trim();
                 }
-                mCallbacks.notifyVolumeMetadataChanged(vol.clone());
+                // TODO: notify listeners that label changed
                 break;
             }
             case VoldResponseCode.VOLUME_PATH_CHANGED: {
@@ -954,6 +906,14 @@
                 }
                 break;
             }
+            case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
+                if (cooked.length != 3) break;
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
+                if (vol != null) {
+                    vol.internalPath = cooked[2];
+                }
+                break;
+            }
             case VoldResponseCode.VOLUME_DESTROYED: {
                 if (cooked.length != 2) break;
                 mVolumes.remove(cooked[1]);
@@ -1068,6 +1028,19 @@
     }
 
     private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
+        // Remember that we saw this volume so we're ready to accept user
+        // metadata, or so we can annoy them when a private volume is ejected
+        if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
+            if (!mRecords.containsKey(vol.fsUuid)) {
+                final VolumeRecord rec = new VolumeRecord(vol.type, vol.fsUuid);
+                if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+                    rec.nickname = vol.disk.getDescription();
+                }
+                mRecords.put(rec.fsUuid, rec);
+                writeSettingsLocked();
+            }
+        }
+
         mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
 
         if (isBroadcastWorthy(vol)) {
@@ -1125,7 +1098,7 @@
             Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
 
             mPrimaryStorageUuid = mMoveTargetUuid;
-            writeMetadataLocked();
+            writeSettingsLocked();
         }
 
         if (PackageManager.isMoveStatusFinished(status)) {
@@ -1136,25 +1109,6 @@
         }
     }
 
-    /**
-     * Refresh latest metadata into any currently active {@link VolumeInfo}.
-     */
-    private void refreshMetadataLocked() {
-        final int size = mVolumes.size();
-        for (int i = 0; i < size; i++) {
-            final VolumeInfo vol = mVolumes.valueAt(i);
-            final VolumeMetadata meta = mMetadata.get(vol.fsUuid);
-
-            if (meta != null) {
-                vol.nickname = meta.nickname;
-                vol.userFlags = meta.userFlags;
-            } else {
-                vol.nickname = null;
-                vol.userFlags = 0;
-            }
-        }
-    }
-
     private void enforcePermission(String perm) {
         mContext.enforceCallingOrSelfPermission(perm, perm);
     }
@@ -1203,11 +1157,11 @@
             mLastMaintenance = mLastMaintenanceFile.lastModified();
         }
 
-        mMetadataFile = new AtomicFile(
+        mSettingsFile = new AtomicFile(
                 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
 
         synchronized (mLock) {
-            readMetadataLocked();
+            readSettingsLocked();
         }
 
         /*
@@ -1233,12 +1187,12 @@
         mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
     }
 
-    private void readMetadataLocked() {
-        mMetadata.clear();
+    private void readSettingsLocked() {
+        mRecords.clear();
 
         FileInputStream fis = null;
         try {
-            fis = mMetadataFile.openRead();
+            fis = mSettingsFile.openRead();
             final XmlPullParser in = Xml.newPullParser();
             in.setInput(fis, null);
 
@@ -1261,8 +1215,8 @@
                         }
 
                     } else if (TAG_VOLUME.equals(tag)) {
-                        final VolumeMetadata meta = VolumeMetadata.read(in);
-                        mMetadata.put(meta.fsUuid, meta);
+                        final VolumeRecord rec = readVolumeRecord(in);
+                        mRecords.put(rec.fsUuid, rec);
                     }
                 }
             }
@@ -1277,10 +1231,10 @@
         }
     }
 
-    private void writeMetadataLocked() {
+    private void writeSettingsLocked() {
         FileOutputStream fos = null;
         try {
-            fos = mMetadataFile.startWrite();
+            fos = mSettingsFile.startWrite();
 
             XmlSerializer out = new FastXmlSerializer();
             out.setOutput(fos, "utf-8");
@@ -1288,22 +1242,40 @@
             out.startTag(null, TAG_VOLUMES);
             writeIntAttribute(out, ATTR_VERSION, VERSION_ADD_PRIMARY);
             writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
-            final int size = mMetadata.size();
+            final int size = mRecords.size();
             for (int i = 0; i < size; i++) {
-                final VolumeMetadata meta = mMetadata.valueAt(i);
-                VolumeMetadata.write(out, meta);
+                final VolumeRecord rec = mRecords.valueAt(i);
+                writeVolumeRecord(out, rec);
             }
             out.endTag(null, TAG_VOLUMES);
             out.endDocument();
 
-            mMetadataFile.finishWrite(fos);
+            mSettingsFile.finishWrite(fos);
         } catch (IOException e) {
             if (fos != null) {
-                mMetadataFile.failWrite(fos);
+                mSettingsFile.failWrite(fos);
             }
         }
     }
 
+    public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
+        final int type = readIntAttribute(in, ATTR_TYPE);
+        final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
+        final VolumeRecord meta = new VolumeRecord(type, fsUuid);
+        meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
+        meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
+        return meta;
+    }
+
+    public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
+        out.startTag(null, TAG_VOLUME);
+        writeIntAttribute(out, ATTR_TYPE, rec.type);
+        writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
+        writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
+        writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
+        out.endTag(null, TAG_VOLUME);
+    }
+
     /**
      * Exposed API calls below here
      */
@@ -1469,32 +1441,68 @@
     }
 
     @Override
-    public void setVolumeNickname(String volId, String nickname) {
+    public void setVolumeNickname(String fsUuid, String nickname) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
 
+        Preconditions.checkNotNull(fsUuid);
         synchronized (mLock) {
-            final VolumeInfo vol = findVolumeById(volId);
-            final VolumeMetadata meta = findOrCreateMetadataLocked(vol);
-            meta.nickname = nickname;
-            refreshMetadataLocked();
-            writeMetadataLocked();
-            mCallbacks.notifyVolumeMetadataChanged(vol.clone());
+            final VolumeRecord rec = mRecords.get(fsUuid);
+            rec.nickname = nickname;
+            mCallbacks.notifyVolumeRecordChanged(rec);
+            writeSettingsLocked();
         }
     }
 
     @Override
-    public void setVolumeUserFlags(String volId, int flags, int mask) {
+    public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
 
+        Preconditions.checkNotNull(fsUuid);
         synchronized (mLock) {
-            final VolumeInfo vol = findVolumeById(volId);
-            final VolumeMetadata meta = findOrCreateMetadataLocked(vol);
-            meta.userFlags = (meta.userFlags & ~mask) | (flags & mask);
-            refreshMetadataLocked();
-            writeMetadataLocked();
-            mCallbacks.notifyVolumeMetadataChanged(vol.clone());
+            final VolumeRecord rec = mRecords.get(fsUuid);
+            rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
+            mCallbacks.notifyVolumeRecordChanged(rec);
+            writeSettingsLocked();
+        }
+    }
+
+    @Override
+    public void forgetVolume(String fsUuid) {
+        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
+
+        Preconditions.checkNotNull(fsUuid);
+        synchronized (mLock) {
+            mRecords.remove(fsUuid);
+
+            // TODO: tell vold to forget keys
+
+            // If this had been primary storage, revert back to internal and
+            // reset vold so we bind into new volume into place.
+            if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
+                mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL;
+                resetIfReadyAndConnected();
+            }
+
+            mCallbacks.notifyVolumeForgotten(fsUuid);
+            writeSettingsLocked();
+        }
+    }
+
+    private void forgetAll() {
+        synchronized (mLock) {
+            for (int i = 0; i < mRecords.size(); i++) {
+                final String fsUuid = mRecords.keyAt(i);
+                mCallbacks.notifyVolumeForgotten(fsUuid);
+            }
+
+            mRecords.clear();
+            writeSettingsLocked();
+
+            mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL;
+            resetIfReadyAndConnected();
         }
     }
 
@@ -2327,11 +2335,6 @@
 
     @Override
     public VolumeInfo[] getVolumes(int flags) {
-        if ((flags & StorageManager.FLAG_ALL_METADATA) != 0) {
-            // TODO: implement support for returning all metadata
-            throw new UnsupportedOperationException();
-        }
-
         synchronized (mLock) {
             final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
             for (int i = 0; i < mVolumes.size(); i++) {
@@ -2341,6 +2344,17 @@
         }
     }
 
+    @Override
+    public VolumeRecord[] getVolumeRecords(int flags) {
+        synchronized (mLock) {
+            final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
+            for (int i = 0; i < mRecords.size(); i++) {
+                res[i] = mRecords.valueAt(i);
+            }
+            return res;
+        }
+    }
+
     private void addObbStateLocked(ObbState obbState) throws RemoteException {
         final IBinder binder = obbState.getBinder();
         List<ObbState> obbStates = mObbMounts.get(binder);
@@ -2844,8 +2858,9 @@
     private static class Callbacks extends Handler {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;
-        private static final int MSG_VOLUME_METADATA_CHANGED = 3;
-        private static final int MSG_DISK_SCANNED = 4;
+        private static final int MSG_VOLUME_RECORD_CHANGED = 3;
+        private static final int MSG_VOLUME_FORGOTTEN = 4;
+        private static final int MSG_DISK_SCANNED = 5;
 
         private final RemoteCallbackList<IMountServiceListener>
                 mCallbacks = new RemoteCallbackList<>();
@@ -2889,8 +2904,12 @@
                     callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
                     break;
                 }
-                case MSG_VOLUME_METADATA_CHANGED: {
-                    callback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
+                case MSG_VOLUME_RECORD_CHANGED: {
+                    callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
+                    break;
+                }
+                case MSG_VOLUME_FORGOTTEN: {
+                    callback.onVolumeForgotten((String) args.arg1);
                     break;
                 }
                 case MSG_DISK_SCANNED: {
@@ -2910,21 +2929,27 @@
 
         private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = vol;
+            args.arg1 = vol.clone();
             args.argi2 = oldState;
             args.argi3 = newState;
             obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
         }
 
-        private void notifyVolumeMetadataChanged(VolumeInfo vol) {
+        private void notifyVolumeRecordChanged(VolumeRecord rec) {
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = vol;
-            obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
+            args.arg1 = rec.clone();
+            obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
+        }
+
+        private void notifyVolumeForgotten(String fsUuid) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = fsUuid;
+            obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
         }
 
         private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = disk;
+            args.arg1 = disk.clone();
             args.argi2 = volumeCount;
             obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
         }
@@ -2935,11 +2960,8 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
         for (String arg : args) {
-            if ("--clear-metadata".equals(arg)) {
-                synchronized (mLock) {
-                    mMetadata.clear();
-                    writeMetadataLocked();
-                }
+            if ("--forget-all".equals(arg)) {
+                forgetAll();
             }
         }
 
@@ -2964,11 +2986,11 @@
             pw.decreaseIndent();
 
             pw.println();
-            pw.println("Metadata:");
+            pw.println("Records:");
             pw.increaseIndent();
-            for (int i = 0; i < mMetadata.size(); i++) {
-                final VolumeMetadata meta = mMetadata.valueAt(i);
-                meta.dump(pw);
+            for (int i = 0; i < mRecords.size(); i++) {
+                final VolumeRecord note = mRecords.valueAt(i);
+                note.dump(pw);
             }
             pw.decreaseIndent();
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b5b62b4..f6998ca 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -43,6 +43,7 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.Network;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
@@ -107,8 +108,8 @@
  */
 public class NetworkManagementService extends INetworkManagementService.Stub
         implements Watchdog.Monitor {
-    private static final String TAG = "NetworkManagementService";
-    private static final boolean DBG = false;
+    private static final String TAG = "NetworkManagement";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String NETD_TAG = "NetdConnector";
     private static final String NETD_SOCKET_NAME = "netd";
 
@@ -188,6 +189,9 @@
     /** Set of UIDs with cleartext penalties. */
     @GuardedBy("mQuotaLock")
     private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
+    /** Set of UIDs that are to be blocked/allowed by firewall controller. */
+    @GuardedBy("mQuotaLock")
+    private SparseIntArray mUidFirewallRules = new SparseIntArray();
 
     private Object mIdleTimerLock = new Object();
     /** Set of interfaces with active idle timers. */
@@ -563,10 +567,19 @@
                     setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
                 }
             }
-        }
 
-        // TODO: Push any existing firewall state
-        setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+            setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+
+            size = mUidFirewallRules.size();
+            if (size > 0) {
+                Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
+                final SparseIntArray uidFirewallRules = mUidFirewallRules;
+                mUidFirewallRules = new SparseIntArray();
+                for (int i = 0; i < uidFirewallRules.size(); i++) {
+                    setFirewallUidRule(uidFirewallRules.keyAt(i), uidFirewallRules.valueAt(i));
+                }
+            }
+        }
     }
 
     /**
@@ -1899,7 +1912,7 @@
     public void setFirewallEnabled(boolean enabled) {
         enforceSystemUid();
         try {
-            mConnector.execute("firewall", enabled ? "enable" : "disable");
+            mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
             mFirewallEnabled = enabled;
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
@@ -1949,14 +1962,48 @@
     }
 
     @Override
-    public void setFirewallUidRule(int uid, boolean allow) {
+    public void setFirewallUidRule(int uid, int rule) {
         enforceSystemUid();
-        Preconditions.checkState(mFirewallEnabled);
-        final String rule = allow ? "allow" : "deny";
-        try {
-            mConnector.execute("firewall", "set_uid_rule", uid, rule);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+        if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+            Preconditions.checkState(mFirewallEnabled);
+        }
+        synchronized (mQuotaLock) {
+            final int oldUidFirewallRule = mUidFirewallRules.get(uid);
+            if (DBG) {
+                Slog.d(TAG, "oldRule = " + oldUidFirewallRule
+                        + ", newRule=" + rule + " for uid=" + uid);
+            }
+            if (oldUidFirewallRule == rule) {
+                if (DBG) Slog.d(TAG, "!!!!! Skipping change");
+                // TODO: eventually consider throwing
+                return;
+            }
+
+            try {
+                String ruleName;
+                if (isFirewallEnabled()) { // Whitelist mode
+                    if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+                        ruleName = "allow";
+                    } else {
+                        ruleName = "deny";
+                    }
+                } else { // Blacklist mode
+                    if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+                        ruleName = "deny";
+                    } else {
+                        ruleName = "allow";
+                    }
+                }
+
+                if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
+                    mUidFirewallRules.delete(uid);
+                } else {
+                    mUidFirewallRules.put(uid, rule);
+                }
+                mConnector.execute("firewall", "set_uid_rule", uid, ruleName);
+            } catch (NativeDaemonConnectorException e) {
+                throw e.rethrowAsParcelableException();
+            }
         }
     }
 
@@ -2072,6 +2119,18 @@
             pw.println("]");
         }
 
+        synchronized (mUidFirewallRules) {
+            pw.print("UID firewall rule: [");
+            final int size = mUidFirewallRules.size();
+            for (int i = 0; i < size; i++) {
+                pw.print(mUidFirewallRules.keyAt(i));
+                pw.print(":");
+                pw.print(mUidFirewallRules.valueAt(i));
+                if (i < size - 1) pw.print(",");
+            }
+            pw.println("]");
+        }
+
         synchronized (mIdleTimerLock) {
             pw.println("Idle timers:");
             for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 4ee6657..8c6e290 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -759,47 +759,50 @@
     }
 
     public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
-        log("notifySignalStrengthForSubscriber: subId=" + subId
-                + " signalStrength=" + signalStrength);
         if (!checkNotifyPermission("notifySignalStrength()")) {
-            log("notifySignalStrengthForSubscriber: permission check failure");
             return;
         }
-        toStringLogSSC("notifySignalStrengthForSubscriber");
+        if (VDBG) {
+            log("notifySignalStrengthForSubscriber: subId=" + subId
+                + " signalStrength=" + signalStrength);
+            toStringLogSSC("notifySignalStrengthForSubscriber");
+        }
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
             if (validatePhoneId(phoneId)) {
-                log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
+                if (VDBG) log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
                 mSignalStrength[phoneId] = signalStrength;
                 for (Record r : mRecords) {
-                    log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
-                            + " phoneId=" + phoneId + " ss=" + signalStrength);
+                    if (VDBG) {
+                        log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
+                                + " phoneId=" + phoneId + " ss=" + signalStrength);
+                    }
                     if (r.matchPhoneStateListenerEvent(
                                 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
-                            log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
-                                    + " subId=" + subId + " phoneId=" + phoneId
-                                    + " ss=" + signalStrength);
+                            if (DBG) {
+                                log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " ss=" + signalStrength);
+                            }
                             r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
                         } catch (RemoteException ex) {
-                            log("notifySignalStrengthForSubscriber: Exception while calling callback!!");
                             mRemoveList.add(r.binder);
                         }
-                    } else {
-                        log("notifySignalStrengthForSubscriber: no match for LISTEN_SIGNAL_STRENGTHS");
                     }
                     if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
                             idMatch(r.subId, subId, phoneId)){
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
-                            log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
-                                    + " subId=" + subId + " phoneId=" + phoneId
-                                    + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
+                            if (DBG) {
+                                log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
+                            }
                             r.callback.onSignalStrengthChanged(ss);
                         } catch (RemoteException ex) {
-                            log("notifySignalStrengthForSubscriber: Exception in deprecated LISTEN_SIGNAL_STRENGTH");
                             mRemoveList.add(r.binder);
                         }
                     }
@@ -807,7 +810,6 @@
             } else {
                 log("notifySignalStrengthForSubscriber: invalid phoneId=" + phoneId);
             }
-            log("notifySignalStrengthForSubscriber: done with all records");
             handleRemoveListLocked();
         }
         broadcastSignalStrengthChanged(signalStrength, subId);
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 9a6f696..5bce6eb 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -555,7 +555,8 @@
         if (DBG) {
             Slog.w(TAG, "bind service: " + info.getId());
         }
-        if (!bindCurrentSpellCheckerService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+        if (!bindCurrentSpellCheckerService(serviceIntent, connection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
             Slog.e(TAG, "Failed to get a spell checker service.");
             return;
         }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 999e91b..62f168d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -54,6 +54,7 @@
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -83,9 +84,12 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -109,7 +113,9 @@
 
     private static final int TIMEOUT_DELAY_MS = 1000 * 60;
     private static final String DATABASE_NAME = "accounts.db";
-    private static final int DATABASE_VERSION = 7;
+    private static final int DATABASE_VERSION = 8;
+
+    private static final int MAX_DEBUG_DB_SIZE = 64;
 
     private final Context mContext;
 
@@ -214,6 +220,9 @@
         private final HashMap<Account, AtomicReference<String>> previousNameCache =
                 new HashMap<Account, AtomicReference<String>>();
 
+        private int debugDbInsertionPoint = -1;
+        private SQLiteStatement statementForLogging;
+
         UserAccounts(Context context, int userId) {
             this.userId = userId;
             synchronized (cacheLock) {
@@ -320,6 +329,8 @@
         UserAccounts accounts = mUsers.get(userId);
         if (accounts == null) {
             accounts = new UserAccounts(mContext, userId);
+            initializeDebugDbSizeAndCompileSqlStatementForLogging(
+                    accounts.openHelper.getWritableDatabase(), accounts);
             mUsers.append(userId, accounts);
             purgeOldGrants(accounts);
             validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
@@ -407,6 +418,10 @@
                                 + accountType + " no longer has a registered authenticator");
                         db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
                         accountDeleted = true;
+
+                        logRecord(db, DebugDbHelper.ACTION_AUTHENTICATOR_REMOVE, TABLE_ACCOUNTS,
+                                accountId, accounts);
+
                         final Account account = new Account(accountName, accountType);
                         accounts.userDataCache.remove(account);
                         accounts.authTokenCache.remove(account);
@@ -666,9 +681,10 @@
 
         UserAccounts accounts = getUserAccountsForCaller();
         // fails if the account already exists
+        int uid = getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
-            return addAccountInternal(accounts, account, password, extras, false);
+            return addAccountInternal(accounts, account, password, extras, false, uid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -811,7 +827,7 @@
     }
 
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras, boolean restricted) {
+            Bundle extras, boolean restricted, int callingUid) {
         if (account == null) {
             return false;
         }
@@ -850,6 +866,10 @@
                     }
                 }
                 db.setTransactionSuccessful();
+
+                logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_ACCOUNTS, accountId,
+                        accounts, callingUid);
+
                 insertAccountIntoCacheLocked(accounts, account);
             } finally {
                 db.endTransaction();
@@ -983,9 +1003,12 @@
         if (accountToRename == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(accountToRename);
         UserAccounts accounts = getUserAccountsForCaller();
+
+        int callingUid = getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
-            Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
+            Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName,
+                    callingUid);
             Bundle result = new Bundle();
             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
@@ -1000,7 +1023,7 @@
     }
 
     private Account renameAccountInternal(
-            UserAccounts accounts, Account accountToRename, String newName) {
+            UserAccounts accounts, Account accountToRename, String newName, int callingUid) {
         Account resultAccount = null;
         /*
          * Cancel existing notifications. Let authenticators
@@ -1038,6 +1061,8 @@
                     db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                     db.setTransactionSuccessful();
                     isSuccessful = true;
+                    logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_ACCOUNTS, accountId,
+                            accounts);
                 }
             } finally {
                 db.endTransaction();
@@ -1131,6 +1156,8 @@
             }
         }
 
+        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
+
         try {
             new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
         } finally {
@@ -1188,6 +1215,8 @@
             }
         }
 
+        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
+
         try {
             new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
         } finally {
@@ -1210,6 +1239,9 @@
         if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
             return false;
         }
+
+        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
+
         long identityToken = clearCallingIdentity();
         try {
             return removeAccountInternal(accounts, account);
@@ -1275,21 +1307,25 @@
         int deleted;
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final long accountId = getAccountIdLocked(db, account);
             deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
                     + "=?",
                     new String[]{account.name, account.type});
             removeAccountFromCacheLocked(accounts, account);
             sendAccountsChangedBroadcast(accounts.userId);
+
+            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
         }
         if (accounts.userId == UserHandle.USER_OWNER) {
             // Owner's account was removed, remove from any users that are sharing
             // this account.
+            int callingUid = getCallingUid();
             long id = Binder.clearCallingIdentity();
             try {
                 List<UserInfo> users = mUserManager.getUsers(true);
                 for (UserInfo user : users) {
                     if (!user.isPrimary() && user.isRestricted()) {
-                        removeSharedAccountAsUser(account, user.id);
+                        removeSharedAccountAsUser(account, user.id, callingUid);
                     }
                 }
             } finally {
@@ -1441,15 +1477,17 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
         UserAccounts accounts = getUserAccountsForCaller();
+        int callingUid = getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
-            setPasswordInternal(accounts, account, password);
+            setPasswordInternal(accounts, account, password, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
-    private void setPasswordInternal(UserAccounts accounts, Account account, String password) {
+    private void setPasswordInternal(UserAccounts accounts, Account account, String password,
+            int callingUid) {
         if (account == null) {
             return;
         }
@@ -1473,6 +1511,11 @@
                     db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                     accounts.authTokenCache.remove(account);
                     db.setTransactionSuccessful();
+
+                    String action = (password == null || password.length() == 0) ?
+                            DebugDbHelper.ACTION_CLEAR_PASSWORD
+                            : DebugDbHelper.ACTION_SET_PASSWORD;
+                    logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts, callingUid);
                 }
             } finally {
                 db.endTransaction();
@@ -1497,9 +1540,11 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         checkManageAccountsPermission();
         UserAccounts accounts = getUserAccountsForCaller();
+
+        int callingUid = getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
-            setPasswordInternal(accounts, account, null);
+            setPasswordInternal(accounts, account, null, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -1888,6 +1933,8 @@
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
 
+        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS);
+
         long identityToken = clearCallingIdentity();
         try {
             new Session(accounts, response, accountType, expectActivityLaunch,
@@ -1964,6 +2011,8 @@
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
 
+        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS);
+
         long identityToken = clearCallingIdentity();
         try {
             new Session(accounts, response, accountType, expectActivityLaunch,
@@ -2320,7 +2369,8 @@
     @Override
     public boolean addSharedAccountAsUser(Account account, int userId) {
         userId = handleIncomingUser(userId);
-        SQLiteDatabase db = getUserAccounts(userId).openHelper.getWritableDatabase();
+        UserAccounts accounts = getUserAccounts(userId);
+        SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
         ContentValues values = new ContentValues();
         values.put(ACCOUNTS_NAME, account.name);
         values.put(ACCOUNTS_TYPE, account.type);
@@ -2332,6 +2382,7 @@
                     + ", skipping the DB insert failed");
             return false;
         }
+        logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_SHARED_ACCOUNTS, accountId, accounts);
         return true;
     }
 
@@ -2340,6 +2391,7 @@
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+        long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
         final ContentValues values = new ContentValues();
         values.put(ACCOUNTS_NAME, newName);
         values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
@@ -2349,20 +2401,30 @@
                 ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
                 new String[] { account.name, account.type });
         if (r > 0) {
+            int callingUid = getCallingUid();
+            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_SHARED_ACCOUNTS,
+                    sharedTableAccountId, accounts, callingUid);
             // Recursively rename the account.
-            renameAccountInternal(accounts, account, newName);
+            renameAccountInternal(accounts, account, newName, callingUid);
         }
         return r > 0;
     }
 
     @Override
     public boolean removeSharedAccountAsUser(Account account, int userId) {
+        return removeSharedAccountAsUser(account, userId, getCallingUid());
+    }
+
+    private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+        long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
         int r = db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
                 new String[] {account.name, account.type});
         if (r > 0) {
+            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
+                    sharedTableAccountId, accounts, callingUid);
             removeAccountInternal(accounts, account);
         }
         return r > 0;
@@ -2459,6 +2521,19 @@
         }
     }
 
+    private long getAccountIdFromSharedTable(SQLiteDatabase db, Account account) {
+        Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_ID},
+                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+            return -1;
+        } finally {
+            cursor.close();
+        }
+    }
+
     private long getAccountIdLocked(SQLiteDatabase db, Account account) {
         Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
                 "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
@@ -2696,26 +2771,10 @@
                                             mAccountName, mAccountType
                                     });
                         }
-                        result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH,
+                        result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
                                 lastAuthenticatedTime);
                     }
                 }
-                if (mAuthDetailsRequired) {
-                    long lastAuthenticatedTime = -1;
-                    if (isAccountPresentForCaller(mAccountName, mAccountType)) {
-                        lastAuthenticatedTime = DatabaseUtils.longForQuery(
-                                mAccounts.openHelper.getReadableDatabase(),
-                                "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " from "
-                                        +
-                                        TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
-                                        + ACCOUNTS_TYPE + "=?",
-                                new String[] {
-                                        mAccountName, mAccountType
-                                });
-                    }
-                    result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH,
-                            lastAuthenticatedTime);
-                }
             }
             if (result != null
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
@@ -2904,6 +2963,130 @@
         return databaseFile.getPath();
     }
 
+    private static class DebugDbHelper{
+        private DebugDbHelper() {
+        }
+
+        private static String TABLE_DEBUG = "debug_table";
+
+        // Columns for the table
+        private static String ACTION_TYPE = "action_type";
+        private static String TIMESTAMP = "time";
+        private static String CALLER_UID = "caller_uid";
+        private static String TABLE_NAME = "table_name";
+        private static String KEY = "primary_key";
+
+        // These actions correspond to the occurrence of real actions. Since
+        // these are called by the authenticators, the uid associated will be
+        // of the authenticator.
+        private static String ACTION_SET_PASSWORD = "action_set_password";
+        private static String ACTION_CLEAR_PASSWORD = "action_clear_password";
+        private static String ACTION_ACCOUNT_ADD = "action_account_add";
+        private static String ACTION_ACCOUNT_REMOVE = "action_account_remove";
+        private static String ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
+        private static String ACTION_ACCOUNT_RENAME = "action_account_rename";
+
+        // These actions don't necessarily correspond to any action on
+        // accountDb taking place. As an example, there might be a request for
+        // addingAccount, which might not lead to addition of account on grounds
+        // of bad authentication. We will still be logging it to keep track of
+        // who called.
+        private static String ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
+        private static String ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
+        private static String ACTION_CALLED_ACCOUNT_RENAME = "action_called_account_rename";
+
+        private static SimpleDateFormat dateFromat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+        private static String UPDATE_WHERE_CLAUSE = KEY + "=?";
+
+        private static void createDebugTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
+                    + ACCOUNTS_ID + " INTEGER,"
+                    + ACTION_TYPE + " TEXT NOT NULL, "
+                    + TIMESTAMP + " DATETIME,"
+                    + CALLER_UID + " INTEGER NOT NULL,"
+                    + TABLE_NAME + " TEXT NOT NULL,"
+                    + KEY + " INTEGER PRIMARY KEY)");
+            db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " (" + TIMESTAMP + ")");
+        }
+    }
+
+    private void logRecord(UserAccounts accounts, String action, String tableName) {
+        SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+        logRecord(db, action, tableName, -1, accounts);
+    }
+
+    /*
+     * This function receives an opened writable database.
+     */
+    private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+            UserAccounts userAccount) {
+        logRecord(db, action, tableName, accountId, userAccount, getCallingUid());
+    }
+
+    /*
+     * This function receives an opened writable database.
+     */
+    private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+            UserAccounts userAccount, int callingUid) {
+        SQLiteStatement logStatement = userAccount.statementForLogging;
+        logStatement.bindLong(1, accountId);
+        logStatement.bindString(2, action);
+        logStatement.bindString(3, DebugDbHelper.dateFromat.format(new Date()));
+        logStatement.bindLong(4, callingUid);
+        logStatement.bindString(5, tableName);
+        logStatement.bindLong(6, userAccount.debugDbInsertionPoint);
+        logStatement.execute();
+        logStatement.clearBindings();
+        userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
+                % MAX_DEBUG_DB_SIZE;
+    }
+
+    /*
+     * This should only be called once to compile the sql statement for logging
+     * and to find the insertion point.
+     */
+    private void initializeDebugDbSizeAndCompileSqlStatementForLogging(SQLiteDatabase db,
+            UserAccounts userAccount) {
+        // Initialize the count if not done earlier.
+        int size = (int) getDebugTableRowCount(db);
+        if (size >= MAX_DEBUG_DB_SIZE) {
+            // Table is full, and we need to find the point where to insert.
+            userAccount.debugDbInsertionPoint = (int) getDebugTableInsertionPoint(db);
+        } else {
+            userAccount.debugDbInsertionPoint = size;
+        }
+        compileSqlStatementForLogging(db, userAccount);
+    }
+
+    private void compileSqlStatementForLogging(SQLiteDatabase db, UserAccounts userAccount) {
+        String sql = "INSERT OR REPLACE INTO " + DebugDbHelper.TABLE_DEBUG
+                + " VALUES (?,?,?,?,?,?)";
+        userAccount.statementForLogging = db.compileStatement(sql);
+    }
+
+    private long getDebugTableRowCount(SQLiteDatabase db) {
+        String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + DebugDbHelper.TABLE_DEBUG;
+        return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+    }
+
+    /*
+     * Finds the row key where the next insertion should take place. This should
+     * be invoked only if the table has reached its full capacity.
+     */
+    private long getDebugTableInsertionPoint(SQLiteDatabase db) {
+        // This query finds the smallest timestamp value (and if 2 records have
+        // same timestamp, the choose the lower id).
+        String queryCountDebugDbRows = new StringBuilder()
+                .append("SELECT ").append(DebugDbHelper.KEY)
+                .append(" FROM ").append(DebugDbHelper.TABLE_DEBUG)
+                .append(" ORDER BY ")
+                .append(DebugDbHelper.TIMESTAMP).append(",").append(DebugDbHelper.KEY)
+                .append(" LIMIT 1")
+                .toString();
+        return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+    }
+
     static class DatabaseHelper extends SQLiteOpenHelper {
 
         public DatabaseHelper(Context context, int userId) {
@@ -2949,6 +3132,8 @@
             createSharedAccountsTable(db);
 
             createAccountsDeletionTrigger(db);
+
+            DebugDbHelper.createDebugTable(db);
         }
 
         private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -2968,6 +3153,10 @@
             db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
         }
 
+        private void addDebugTable(SQLiteDatabase db) {
+            DebugDbHelper.createDebugTable(db);
+        }
+
         private void createAccountsDeletionTrigger(SQLiteDatabase db) {
             db.execSQL(""
                     + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
@@ -3028,6 +3217,11 @@
                 oldVersion++;
             }
 
+            if (oldVersion == 7) {
+                addDebugTable(db);
+                oldVersion++;
+            }
+
             if (oldVersion != newVersion) {
                 Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
             }
@@ -3109,6 +3303,23 @@
                     fout.println("  " + account);
                 }
 
+                // Add debug information.
+                fout.println();
+                Cursor cursor = db.query(DebugDbHelper.TABLE_DEBUG, null,
+                        null, null, null, null, DebugDbHelper.TIMESTAMP);
+                fout.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
+                fout.println("Accounts History");
+                try {
+                    while (cursor.moveToNext()) {
+                        // print type,count
+                        fout.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
+                                cursor.getString(2) + "," + cursor.getString(3) + ","
+                                + cursor.getString(4) + "," + cursor.getString(5));
+                    }
+                } finally {
+                    cursor.close();
+                }
+
                 fout.println();
                 synchronized (mSessions) {
                     final long now = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 15d7367..069878e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -699,12 +699,10 @@
     private final StringBuilder mStrictModeBuffer = new StringBuilder();
 
     /**
-     * Keeps track of all IIntentReceivers that have been registered for
-     * broadcasts.  Hash keys are the receiver IBinder, hash value is
-     * a ReceiverList.
+     * Keeps track of all IIntentReceivers that have been registered for broadcasts.
+     * Hash keys are the receiver IBinder, hash value is a ReceiverList.
      */
-    final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
-            new HashMap<IBinder, ReceiverList>();
+    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
 
     /**
      * Resolver for broadcast intents to registered receivers.
@@ -716,7 +714,7 @@
         protected boolean allowFilterResult(
                 BroadcastFilter filter, List<BroadcastFilter> dest) {
             IBinder target = filter.receiverList.receiver.asBinder();
-            for (int i=dest.size()-1; i>=0; i--) {
+            for (int i = dest.size() - 1; i >= 0; i--) {
                 if (dest.get(i).receiverList.receiver.asBinder() == target) {
                     return false;
                 }
@@ -3115,8 +3113,16 @@
         checkTime(startTime, "startProcess: done updating cpu stats");
 
         try {
-            int uid = app.uid;
+            try {
+                if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) {
+                    // This is caught below as if we had failed to fork zygote
+                    throw new RuntimeException("Package " + app.info.packageName + " is frozen!");
+                }
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
 
+            int uid = app.uid;
             int[] gids = null;
             int mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
             if (!app.isolated) {
@@ -3126,7 +3132,7 @@
                     permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName,
                             app.userId);
                 } catch (RemoteException e) {
-                    Slog.w(TAG, "Unable to retrieve gids", e);
+                    throw e.rethrowAsRuntimeException();
                 }
 
                 /*
@@ -3179,6 +3185,10 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_JIT;
                 }
             }
+            String genCFIDebugProperty = SystemProperties.get("debug.gencfi");
+            if ("true".equals(genCFIDebugProperty)) {
+                debugFlags |= Zygote.DEBUG_GENERATE_CFI;
+            }
             if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
                 debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
             }
@@ -6603,6 +6613,12 @@
             return mActivityManagerService.checkPermission(permission, pid,
                     uid) == PackageManager.PERMISSION_GRANTED;
         }
+
+        @Override
+        public String[] getPackagesForUid(int uid) {
+            return mActivityManagerService.mContext.getPackageManager()
+                    .getPackagesForUid(uid);
+        }
     }
 
     class IntentFirewallInterface implements IntentFirewall.AMSInterface {
@@ -10874,8 +10890,8 @@
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord proc = mLruProcesses.get(i);
                 if (proc.notCachedSinceIdle) {
-                    if (proc.setProcState != ActivityManager.PROCESS_STATE_TOP
-                            && proc.setProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                    if (proc.setProcState != ActivityManager.PROCESS_STATE_TOP_SLEEPING
+                            && proc.setProcState >= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
                             && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
                         if (doKilling && proc.initialIdlePss != 0
                                 && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
@@ -15656,8 +15672,7 @@
                 // Original caller already died
                 return null;
             }
-            ReceiverList rl
-                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
             if (rl == null) {
                 rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                         userId, receiver);
@@ -15689,7 +15704,7 @@
                     permission, callingUid, userId);
             rl.add(bf);
             if (!bf.debugCheck()) {
-                Slog.w(TAG, "==> For Dynamic broadast");
+                Slog.w(TAG, "==> For Dynamic broadcast");
             }
             mReceiverResolver.addFilter(bf);
 
@@ -15699,9 +15714,9 @@
                 ArrayList receivers = new ArrayList();
                 receivers.add(bf);
 
-                int N = allSticky.size();
-                for (int i=0; i<N; i++) {
-                    Intent intent = (Intent)allSticky.get(i);
+                final int stickyCount = allSticky.size();
+                for (int i = 0; i < stickyCount; i++) {
+                    Intent intent = allSticky.get(i);
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
@@ -15761,8 +15776,7 @@
 
     void removeReceiverLocked(ReceiverList rl) {
         mRegisteredReceivers.remove(rl.receiver.asBinder());
-        int N = rl.size();
-        for (int i=0; i<N; i++) {
+        for (int i = rl.size() - 1; i >= 0; i--) {
             mReceiverResolver.removeFilter(rl.get(i));
         }
     }
@@ -16133,24 +16147,24 @@
             }
             ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
             if (stickies == null) {
-                stickies = new ArrayMap<String, ArrayList<Intent>>();
+                stickies = new ArrayMap<>();
                 mStickyBroadcasts.put(userId, stickies);
             }
             ArrayList<Intent> list = stickies.get(intent.getAction());
             if (list == null) {
-                list = new ArrayList<Intent>();
+                list = new ArrayList<>();
                 stickies.put(intent.getAction(), list);
             }
-            int N = list.size();
+            final int stickiesCount = list.size();
             int i;
-            for (i=0; i<N; i++) {
+            for (i = 0; i < stickiesCount; i++) {
                 if (intent.filterEquals(list.get(i))) {
                     // This sticky already exists, replace it.
                     list.set(i, new Intent(intent));
                     break;
                 }
             }
-            if (i >= N) {
+            if (i >= stickiesCount) {
                 list.add(new Intent(intent));
             }
         }
@@ -17036,7 +17050,7 @@
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
-            procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
         } else if ((queue = isReceivingBroadcast(app)) != null) {
             // An app that is currently receiving a broadcast also
             // counts as being in the foreground for OOM killer purposes.
@@ -17374,8 +17388,19 @@
                                     // processes).  These should not bring the current process
                                     // into the top state, since they are not on top.  Instead
                                     // give them the best state after that.
-                                    clientProcState =
-                                            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                                    if ((cr.flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+                                    } else if (mWakefulness
+                                                    == PowerManagerInternal.WAKEFULNESS_AWAKE &&
+                                            (cr.flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
+                                                    != 0) {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+                                    } else {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                                    }
                                 }
                             }
                         } else {
@@ -17485,7 +17510,7 @@
                         // into the top state, since they are not on top.  Instead
                         // give them the best state after that.
                         clientProcState =
-                                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                     }
                 }
                 if (procState > clientProcState) {
@@ -17525,7 +17550,7 @@
                 case ActivityManager.PROCESS_STATE_SERVICE:
                     // These all are longer-term states, so pull them up to the top
                     // of the background states, but not all the way to the top state.
-                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                    procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                     break;
                 default:
                     // Otherwise, top is a better choice, so take it.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 33f915f..62d70d2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1331,6 +1331,9 @@
                             }
                         } catch(RemoteException e) {
                         }
+                        if (r.state == ActivityState.RESUMED) {
+                            noStackActivityResumed = false;
+                        }
                     } else {
                         // This activity is not currently visible, but is running.
                         // Tell it to become visible.
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a91a7ca..e5c5dff 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -309,7 +309,6 @@
     }
 
     public void skipCurrentReceiverLocked(ProcessRecord app) {
-        boolean reschedule = false;
         BroadcastRecord r = app.curReceiver;
         if (r != null && r.queue == this) {
             // The current broadcast is waiting for this app's receiver
@@ -318,7 +317,6 @@
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
                     r.resultExtras, r.resultAbort, false);
-            reschedule = true;
         }
         if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 423e540..cd37041 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -87,7 +87,16 @@
             sb.append("IMP ");
         }
         if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
-            sb.append("ACT ");
+            sb.append("WACT ");
+        }
+        if ((flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE) != 0) {
+            sb.append("FGSA ");
+        }
+        if ((flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
+            sb.append("FGS ");
+        }
+        if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
+            sb.append("LACT ");
         }
         if ((flags&Context.BIND_VISIBLE) != 0) {
             sb.append("VIS ");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6b56279..06fba34 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -65,6 +65,7 @@
 import android.media.VolumePolicy;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
+import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
@@ -206,6 +207,7 @@
     private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
     private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
     private static final int MSG_UNMUTE_STREAM = 24;
+    private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1803,9 +1805,7 @@
             if (!shouldMute) {
                 // unmute
                 // ring and notifications volume should never be 0 when not silenced
-                // on voice capable devices or devices that support vibration
-                if ((isPlatformVoice() || mHasVibrator) &&
-                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
+                if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                     synchronized (VolumeStreamState.class) {
                         final VolumeStreamState vss = mStreamStates[streamType];
                         for (int i = 0; i < vss.mIndexMap.size(); i++) {
@@ -2986,10 +2986,7 @@
                         mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
                     }
                 } else {
-                    // (oldIndex < step) is equivalent to (old UI index == 0)
-                    if ((oldIndex < step)
-                            && mVolumePolicy.volumeDownToEnterSilent
-                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                    if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
                         ringerMode = RINGER_MODE_SILENT;
                     }
                 }
@@ -3018,7 +3015,8 @@
                     if (mVolumePolicy.volumeDownToEnterSilent) {
                         final long diff = SystemClock.uptimeMillis()
                                 - mLoweredFromNormalToVibrateTime;
-                        if (diff > mVolumePolicy.vibrateToSilentDebounce) {
+                        if (diff > mVolumePolicy.vibrateToSilentDebounce
+                                && mRingerModeDelegate.canVolumeDownEnterSilent()) {
                             ringerMode = RINGER_MODE_SILENT;
                         }
                     } else {
@@ -4341,6 +4339,9 @@
                 case MSG_UNMUTE_STREAM:
                     onUnmuteStream(msg.arg1, msg.arg2);
                     break;
+                case MSG_DYN_POLICY_MIX_STATE_UPDATE:
+                    onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
+                    break;
             }
         }
     }
@@ -5762,6 +5763,8 @@
     //==========================================================================================
     public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
             boolean hasFocusListener) {
+        AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
+
         if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
                 + " with config:" + policyConfig);
         String regId = null;
@@ -5857,6 +5860,39 @@
     }
 
     //======================
+    // Audio policy callback from AudioSystem
+    //======================
+    private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
+            new AudioSystem.DynamicPolicyCallback() {
+        public void onDynamicPolicyMixStateUpdate(String regId, int state) {
+            if (!TextUtils.isEmpty(regId)) {
+                sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
+                        state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
+            }
+        }
+    };
+
+    private void onDynPolicyMixStateUpdate(String regId, int state) {
+        if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
+        synchronized (mAudioPolicies) {
+            for (AudioPolicyProxy policy : mAudioPolicies.values()) {
+                for (AudioMix mix : policy.getMixes()) {
+                    if (mix.getRegistration().equals(regId)) {
+                        try {
+                            policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
+                                    + policy.mPolicyCallback.asBinder(), e);
+                        }
+                        return;
+                    }
+                }
+            }
+        }
+
+    }
+
+    //======================
     // Audio policy proxy
     //======================
     /**
@@ -5865,8 +5901,7 @@
      */
     public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
         private static final String TAG = "AudioPolicyProxy";
-        AudioPolicyConfig mConfig;
-        IAudioPolicyCallback mPolicyToken;
+        IAudioPolicyCallback mPolicyCallback;
         boolean mHasFocusListener;
         /**
          * Audio focus ducking behavior for an audio policy.
@@ -5881,19 +5916,19 @@
                 boolean hasFocusListener) {
             super(config);
             setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
-            mPolicyToken = token;
+            mPolicyCallback = token;
             mHasFocusListener = hasFocusListener;
             if (mHasFocusListener) {
-                mMediaFocusControl.addFocusFollower(mPolicyToken);
+                mMediaFocusControl.addFocusFollower(mPolicyCallback);
             }
             connectMixes();
         }
 
         public void binderDied() {
             synchronized (mAudioPolicies) {
-                Log.i(TAG, "audio policy " + mPolicyToken + " died");
+                Log.i(TAG, "audio policy " + mPolicyCallback + " died");
                 release();
-                mAudioPolicies.remove(mPolicyToken.asBinder());
+                mAudioPolicies.remove(mPolicyCallback.asBinder());
             }
         }
 
@@ -5906,7 +5941,7 @@
                 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
             }
             if (mHasFocusListener) {
-                mMediaFocusControl.removeFocusFollower(mPolicyToken);
+                mMediaFocusControl.removeFocusFollower(mPolicyCallback);
             }
             AudioSystem.registerPolicyMixes(mMixes, false);
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3d478f9..a07591c9 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -529,8 +529,9 @@
                 throw new IllegalArgumentException("At least one address must be specified");
             }
             Connection connection = new Connection();
-            if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
-                        new UserHandle(mUserHandle))) {
+            if (!mContext.bindServiceAsUser(intent, connection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                    new UserHandle(mUserHandle))) {
                 throw new IllegalStateException("Cannot bind " + config.user);
             }
 
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 93d37f1..e15bca6 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
@@ -31,13 +32,13 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
+import android.util.EventLog;
 import android.util.MathUtils;
 import android.util.Spline;
 import android.util.Slog;
 import android.util.TimeUtils;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 
 class AutomaticBrightnessController {
     private static final String TAG = "AutomaticBrightnessController";
@@ -87,7 +88,12 @@
     // well after dusk.
     private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
 
+    // Debounce for sampling user-initiated changes in display brightness to ensure
+    // the user is satisfied with the result before storing the sample.
+    private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
+
     private static final int MSG_UPDATE_AMBIENT_LUX = 1;
+    private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
 
     // Callbacks for requesting updates to the the display's power state
     private final Callbacks mCallbacks;
@@ -179,6 +185,14 @@
     // Are we going to adjust brightness while dozing.
     private boolean mDozing;
 
+    // True if we are collecting a brightness adjustment sample, along with some data
+    // for the initial state of the sample.
+    private boolean mBrightnessAdjustmentSamplePending;
+    private float mBrightnessAdjustmentSampleOldAdjustment;
+    private float mBrightnessAdjustmentSampleOldLux;
+    private int mBrightnessAdjustmentSampleOldBrightness;
+    private float mBrightnessAdjustmentSampleOldGamma;
+
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
             int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -216,7 +230,8 @@
         return mScreenAutoBrightness;
     }
 
-    public void configure(boolean enable, float adjustment, boolean dozing) {
+    public void configure(boolean enable, float adjustment, boolean dozing,
+            boolean userInitiatedChange) {
         // While dozing, the application processor may be suspended which will prevent us from
         // receiving new information from the light sensor. On some devices, we may be able to
         // switch to a wake-up light sensor instead but for now we will simply disable the sensor
@@ -228,6 +243,9 @@
         if (changed) {
             updateAutoBrightness(false /*sendUpdate*/);
         }
+        if (enable && !dozing && userInitiatedChange) {
+            prepareBrightnessAdjustmentSample();
+        }
     }
 
     public void dump(PrintWriter pw) {
@@ -486,7 +504,7 @@
         }
 
         int newScreenAutoBrightness =
-            clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
+                clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
         if (mScreenAutoBrightness != newScreenAutoBrightness) {
             if (DEBUG) {
                 Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
@@ -507,6 +525,54 @@
                 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
     }
 
+    private void prepareBrightnessAdjustmentSample() {
+        if (!mBrightnessAdjustmentSamplePending) {
+            mBrightnessAdjustmentSamplePending = true;
+            mBrightnessAdjustmentSampleOldAdjustment = mScreenAutoBrightnessAdjustment;
+            mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
+            mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
+            mBrightnessAdjustmentSampleOldGamma = mLastScreenAutoBrightnessGamma;
+        } else {
+            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
+        }
+
+        mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
+                BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
+    }
+
+    private void cancelBrightnessAdjustmentSample() {
+        if (mBrightnessAdjustmentSamplePending) {
+            mBrightnessAdjustmentSamplePending = false;
+            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
+        }
+    }
+
+    private void collectBrightnessAdjustmentSample() {
+        if (mBrightnessAdjustmentSamplePending) {
+            mBrightnessAdjustmentSamplePending = false;
+            if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Auto-brightness adjustment changed by user: "
+                            + "adj=" + mScreenAutoBrightnessAdjustment
+                            + ", lux=" + mAmbientLux
+                            + ", brightness=" + mScreenAutoBrightness
+                            + ", gamma=" + mLastScreenAutoBrightnessGamma
+                            + ", ring=" + mAmbientLightRingBuffer);
+                }
+
+                EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
+                        mBrightnessAdjustmentSampleOldAdjustment,
+                        mBrightnessAdjustmentSampleOldLux,
+                        mBrightnessAdjustmentSampleOldBrightness,
+                        mBrightnessAdjustmentSampleOldGamma,
+                        mScreenAutoBrightnessAdjustment,
+                        mAmbientLux,
+                        mScreenAutoBrightness,
+                        mLastScreenAutoBrightnessGamma);
+            }
+        }
+    }
+
     private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
         if (lastSunset < 0 || nextSunrise < 0
                 || now < lastSunset || now > nextSunrise) {
@@ -537,6 +603,10 @@
                 case MSG_UPDATE_AMBIENT_LUX:
                     updateAmbientLux();
                     break;
+
+                case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
+                    collectBrightnessAdjustmentSample();
+                    break;
             }
         }
     }
@@ -584,11 +654,7 @@
         private int mCount;
 
         public AmbientLightRingBuffer(long lightSensorRate) {
-            this((int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate));
-        }
-
-        public AmbientLightRingBuffer(int initialCapacity) {
-            mCapacity = initialCapacity;
+            mCapacity = (int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate);
             mRingLux = new float[mCapacity];
             mRingTime = new long[mCapacity];
         }
@@ -664,10 +730,6 @@
             return mCount;
         }
 
-        public boolean isEmpty() {
-            return mCount == 0;
-        }
-
         public void clear() {
             mStart = 0;
             mEnd = 0;
@@ -676,27 +738,20 @@
 
         @Override
         public String toString() {
-            final int length = mCapacity - mStart;
-            float[] lux = new float[mCount];
-            long[] time = new long[mCount];
-
-            if (mCount <= length) {
-                System.arraycopy(mRingLux, mStart, lux, 0, mCount);
-                System.arraycopy(mRingTime, mStart, time, 0, mCount);
-            } else {
-                System.arraycopy(mRingLux, mStart, lux, 0, length);
-                System.arraycopy(mRingLux, 0, lux, length, mCount - length);
-
-                System.arraycopy(mRingTime, mStart, time, 0, length);
-                System.arraycopy(mRingTime, 0, time, length, mCount - length);
+            StringBuffer buf = new StringBuffer();
+            buf.append('[');
+            for (int i = 0; i < mCount; i++) {
+                final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
+                if (i != 0) {
+                    buf.append(", ");
+                }
+                buf.append(getLux(i));
+                buf.append(" / ");
+                buf.append(next - getTime(i));
+                buf.append("ms");
             }
-            return "AmbientLightRingBuffer{mCapacity=" + mCapacity
-                + ", mStart=" + mStart
-                + ", mEnd=" + mEnd
-                + ", mCount=" + mCount
-                + ", mRingLux=" + Arrays.toString(lux)
-                + ", mRingTime=" + Arrays.toString(time)
-                + "}";
+            buf.append(']');
+            return buf.toString();
         }
 
         private int offsetOf(int index) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f74601e..35fbef6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -70,12 +70,11 @@
  */
 final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
     private static final String TAG = "DisplayPowerController";
+    private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
 
     private static boolean DEBUG = false;
     private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
 
-    private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
-
     // If true, uses the color fade on animation.
     // We might want to turn this off if we cannot get a guarantee that the screen
     // actually turns on and starts showing new content after the call to set the
@@ -599,8 +598,11 @@
             autoBrightnessEnabled = mPowerRequest.useAutoBrightness
                     && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
                     && brightness < 0;
+            final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
+                    && mPowerRequest.brightnessSetByUser;
             mAutomaticBrightnessController.configure(autoBrightnessEnabled,
-                    mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON);
+                    mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
+                    userInitiatedChange);
         }
 
         // Apply brightness boost.
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index 31c1eea..8932ca0 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -775,7 +775,7 @@
                         handleConnectionFailure(false);
                     }
                 }
-            }, mHandler);
+            }, mHandler, mContext.getOpPackageName());
 
             // Use extended timeout value for certification, as some tests require user inputs
             int rtspTimeout = mWifiDisplayCertMode ?
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 768ccf2..cff4814 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -136,7 +136,8 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             try {
                 if (!mContext.bindServiceAsUser(intent, mCurrentDream,
-                        Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        new UserHandle(userId))) {
                     Slog.e(TAG, "Unable to bind dream service: " + intent);
                     stopDream(true /*immediate*/);
                     return;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6b5908d..ed8519a 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,14 +16,15 @@
 
 package com.android.server.fingerprint;
 
+import android.app.AppOpsManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.RemoteException;
-import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.server.SystemService;
@@ -39,6 +40,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -55,6 +57,8 @@
     private ClientMonitor mEnrollClient = null;
     private ClientMonitor mRemoveClient = null;
 
+    private final AppOpsManager mAppOps;
+
     private static final int MSG_NOTIFY = 10;
 
     private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
@@ -96,6 +100,7 @@
     public FingerprintService(Context context) {
         super(context);
         mContext = context;
+        mAppOps = context.getSystemService(AppOpsManager.class);
         nativeInit(Looper.getMainLooper().getQueue(), this);
     }
 
@@ -361,6 +366,13 @@
                 "Must have " + permission + " permission.");
     }
 
+    private boolean canUserFingerPrint(String opPackageName) {
+        checkPermission(USE_FINGERPRINT);
+
+        return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
+                opPackageName) == AppOpsManager.MODE_ALLOWED;
+    }
+
     private class ClientMonitor implements IBinder.DeathRecipient {
         IBinder token;
         IFingerprintServiceReceiver receiver;
@@ -522,8 +534,11 @@
         @Override
         // Binder call
         public void authenticate(final IBinder token, final long opId, final int groupId,
-                final IFingerprintServiceReceiver receiver, final int flags) {
+                final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) {
             checkPermission(USE_FINGERPRINT);
+            if (!canUserFingerPrint(opPackageName)) {
+                return;
+            }
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -535,8 +550,10 @@
         @Override
 
         // Binder call
-        public void cancelAuthentication(final IBinder token) {
-            checkPermission(USE_FINGERPRINT);
+        public void cancelAuthentication(final IBinder token, String opPackageName) {
+            if (!canUserFingerPrint(opPackageName)) {
+                return;
+            }
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -561,8 +578,10 @@
 
         @Override
         // Binder call
-        public boolean isHardwareDetected(long deviceId) {
-            checkPermission(USE_FINGERPRINT);
+        public boolean isHardwareDetected(long deviceId, String opPackageName) {
+            if (!canUserFingerPrint(opPackageName)) {
+                return false;
+            }
             return mHalDeviceId != 0; // TODO
         }
 
@@ -580,21 +599,27 @@
 
         @Override
         // Binder call
-        public List<Fingerprint> getEnrolledFingerprints(int groupId) {
-            checkPermission(USE_FINGERPRINT);
+        public List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName) {
+            if (!canUserFingerPrint(opPackageName)) {
+                return Collections.emptyList();
+            }
             return FingerprintService.this.getEnrolledFingerprints(groupId);
         }
 
         @Override
         // Binder call
-        public boolean hasEnrolledFingerprints(int groupId) {
-            checkPermission(USE_FINGERPRINT);
+        public boolean hasEnrolledFingerprints(int groupId, String opPackageName) {
+            if (!canUserFingerPrint(opPackageName)) {
+                return false;
+            }
             return FingerprintService.this.hasEnrolledFingerprints(groupId);
         }
 
         @Override
-        public long getAuthenticatorId() {
-            checkPermission(USE_FINGERPRINT);
+        public long getAuthenticatorId(String opPackageName) {
+            if (!canUserFingerPrint(opPackageName)) {
+                return 0;
+            }
             return nativeGetAuthenticatorId();
         }
     }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 53ceb2e..b066d6b 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -68,7 +68,7 @@
     private static final int defaultMaxActiveJobsPerService =
             ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
     /** Amount of time a job is allowed to execute for before being considered timed-out. */
-    private static final long EXECUTING_TIMESLICE_MILLIS = 60 * 1000;
+    private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;
     /** Amount of time the JobScheduler will wait for a response from an app for a message. */
     private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
 
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index d3240ec..6bd646d 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -952,13 +952,18 @@
                     return GPS_POSITION_MODE_STANDALONE;
                 }
             }
+            // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
+            // such mode when it is available
+            if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
+                return GPS_POSITION_MODE_MS_BASED;
+            }
+            // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
+            // do fallback only for single-shot requests, because it is too expensive to do for
+            // periodic requests as well
             if (singleShot
                     && hasCapability(GPS_CAPABILITY_MSA)
                     && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
                 return GPS_POSITION_MODE_MS_ASSISTED;
-            } else if (hasCapability(GPS_CAPABILITY_MSB)
-                    && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
-                return GPS_POSITION_MODE_MS_BASED;
             }
         }
         return GPS_POSITION_MODE_STANDALONE;
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
index a5fe9f2..ba98a0a 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -190,7 +190,8 @@
             Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
             service.setComponent(mComponentName);
             try {
-                mBound = mContext.bindServiceAsUser(service, this, Context.BIND_AUTO_CREATE,
+                mBound = mContext.bindServiceAsUser(service, this,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                         new UserHandle(mUserId));
                 if (!mBound && DEBUG) {
                     Slog.d(TAG, this + ": Bind failed");
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 6ffe6ac..0f88883 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -31,6 +33,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
+import android.net.NetworkPolicyManager;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.security.Credentials;
@@ -198,8 +201,8 @@
                     setFirewallEgressSourceRule(addr, true);
                 }
 
-                mNetService.setFirewallUidRule(ROOT_UID, true);
-                mNetService.setFirewallUidRule(Os.getuid(), true);
+                mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW);
+                mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW);
 
                 mErrorCount = 0;
                 mAcceptedIface = iface;
@@ -288,8 +291,8 @@
                     setFirewallEgressSourceRule(addr, false);
                 }
 
-                mNetService.setFirewallUidRule(ROOT_UID, false);
-                mNetService.setFirewallUidRule(Os.getuid(), false);
+                mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT);
+                mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT);
 
                 mAcceptedSourceAddr = null;
             }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 818f0aa..0ae6735 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -36,11 +36,14 @@
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.dumpPolicy;
 import static android.net.NetworkPolicyManager.dumpRules;
@@ -80,6 +83,8 @@
 import android.app.IProcessObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -88,6 +93,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
@@ -110,13 +116,16 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IDeviceIdleController;
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -137,7 +146,6 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
-import com.android.server.AppOpsService;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -145,6 +153,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.AppOpsService;
+import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
@@ -172,7 +182,8 @@
  * and delivers to listeners, such as {@link ConnectivityManager}, for
  * enforcement.
  */
-public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
+        implements AppIdleStateChangeListener {
     private static final String TAG = "NetworkPolicy";
     private static final boolean LOGD = false;
     private static final boolean LOGV = false;
@@ -240,11 +251,13 @@
     private final IPowerManager mPowerManager;
     private final INetworkStatsService mNetworkStats;
     private final INetworkManagementService mNetworkManager;
+    private UsageStatsManagerInternal mUsageStats;
     private final TrustedTime mTime;
 
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
     private PowerManagerInternal mPowerManagerInternal;
+    private IDeviceIdleController mDeviceIdleController;
 
     final Object mRulesLock = new Object();
 
@@ -321,6 +334,8 @@
         mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
+        mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
+                DeviceIdleController.SERVICE_NAME));
         mTime = checkNotNull(time, "missing TrustedTime");
 
         HandlerThread thread = new HandlerThread(TAG);
@@ -342,28 +357,31 @@
         mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
     }
 
+    void updatePowerSaveWhitelistLocked() {
+        try {
+            final int[] whitelist = mDeviceIdleController.getAppIdWhitelist();
+            mPowerSaveWhitelistAppIds.clear();
+            if (whitelist != null) {
+                for (int uid : whitelist) {
+                    mPowerSaveWhitelistAppIds.put(uid, true);
+                }
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     public void systemReady() {
         if (!isBandwidthControlEnabled()) {
             Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
             return;
         }
 
+        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+
         final PackageManager pm = mContext.getPackageManager();
 
         synchronized (mRulesLock) {
-            SystemConfig sysConfig = SystemConfig.getInstance();
-            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
-            for (int i=0; i<allowPower.size(); i++) {
-                String pkg = allowPower.valueAt(i);
-                try {
-                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
-                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
-                    }
-                } catch (PackageManager.NameNotFoundException e) {
-                }
-            }
-
+            updatePowerSaveWhitelistLocked();
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
             mPowerManagerInternal.registerLowPowerModeObserver(
                     new PowerManagerInternal.LowPowerModeListener() {
@@ -406,6 +424,11 @@
         screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
+        // listen for changes to power save whitelist
+        final IntentFilter whitelistFilter = new IntentFilter(
+                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
+
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -449,6 +472,8 @@
                 WifiManager.NETWORK_STATE_CHANGED_ACTION);
         mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
 
+        mUsageStats.addAppIdleStateChangeListener(this);
+
     }
 
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -489,6 +514,17 @@
         }
     };
 
+    private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
+            synchronized (mRulesLock) {
+                updatePowerSaveWhitelistLocked();
+                updateRulesForGlobalChangeLocked(false);
+            }
+        }
+    };
+
     private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -546,12 +582,17 @@
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
             if (userId == -1) return;
 
-            synchronized (mRulesLock) {
-                // Remove any policies for given user; both cleaning up after a
-                // USER_REMOVED, and one last sanity check during USER_ADDED
-                removePoliciesForUserLocked(userId);
-                // Update global restrict for new user
-                updateRulesForGlobalChangeLocked(true);
+            switch (action) {
+                case ACTION_USER_REMOVED:
+                case ACTION_USER_ADDED:
+                    synchronized (mRulesLock) {
+                        // Remove any policies for given user; both cleaning up after a
+                        // USER_REMOVED, and one last sanity check during USER_ADDED
+                        removePoliciesForUserLocked(userId);
+                        // Update global restrict for new user
+                        updateRulesForGlobalChangeLocked(true);
+                    }
+                    break;
             }
         }
     };
@@ -1528,20 +1569,6 @@
         return uids;
     }
 
-    @Override
-    public int[] getPowerSaveAppIdWhitelist() {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
-        synchronized (mRulesLock) {
-            int size = mPowerSaveWhitelistAppIds.size();
-            int[] appids = new int[size];
-            for (int i = 0; i < size; i++) {
-                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
-            }
-            return appids;
-        }
-    }
-
     /**
      * Remove any policies associated with given {@link UserHandle}, persisting
      * if any changes are made.
@@ -1996,7 +2023,7 @@
         // to have data access.  Otherwise, we restrict data access to only
         // the top apps.
         mCurForegroundState = (!mRestrictBackground && (mRestrictPower || mDeviceIdleMode))
-                ? ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                ? ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
                 : ActivityManager.PROCESS_STATE_TOP;
 
         // update rules for all installed applications
@@ -2032,6 +2059,22 @@
         return false;
     }
 
+    private boolean isUidIdle(int uid) {
+        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        final int userId = UserHandle.getUserId(uid);
+
+        for (String packageName : packages) {
+            if (!mUsageStats.isAppIdle(packageName, userId)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Applies network rules to bandwidth and firewall controllers based on uid policy.
+     * @param uid The uid for which to apply the latest policy
+     */
     void updateRulesForUidLocked(int uid) {
         if (!isUidValidForRules(uid)) return;
 
@@ -2048,10 +2091,14 @@
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
+        final boolean uidIdle = isUidIdle(uid);
 
         // derive active rules based on policy and active state
+
         int uidRules = RULE_ALLOW_ALL;
-        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+        if (uidIdle && !mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid))) {
+            uidRules = RULE_REJECT_ALL;
+        } else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
             uidRules = RULE_REJECT_METERED;
         } else if (mRestrictBackground) {
@@ -2070,7 +2117,7 @@
             }
         }
 
-        // TODO: only dispatch when rules actually change
+        final int oldRules = mUidRules.get(uid);
 
         if (uidRules == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
@@ -2078,11 +2125,24 @@
             mUidRules.put(uid, uidRules);
         }
 
+        // Update bandwidth rules if necessary
+        final boolean oldRejectMetered = (oldRules & RULE_REJECT_METERED) != 0;
         final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
-        setUidNetworkRules(uid, rejectMetered);
+        if (oldRejectMetered != rejectMetered) {
+            setUidNetworkRules(uid, rejectMetered);
+        }
+
+        // Update firewall rules if necessary
+        final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0;
+        final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
+        if (oldFirewallReject != firewallReject) {
+            setUidFirewallRules(uid, firewallReject);
+        }
 
         // dispatch changed rule to existing listeners
-        mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+        if (oldRules != uidRules) {
+            mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+        }
 
         try {
             // adjust stats accounting based on foreground status
@@ -2092,6 +2152,18 @@
         }
     }
 
+    @Override
+    public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+            synchronized (mRulesLock) {
+                updateRulesForUidLocked(uid);
+            }
+        } catch (NameNotFoundException nnfe) {
+            return;
+        }
+    }
+
     private Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -2215,6 +2287,22 @@
         }
     }
 
+    /**
+     * Add or remove a uid to the firewall blacklist for all network ifaces.
+     * @param uid
+     * @param rejectOnAll
+     */
+    private void setUidFirewallRules(int uid, boolean rejectOnAll) {
+        try {
+            mNetworkManager.setFirewallUidRule(uid,
+                    rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem setting firewall uid rules", e);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
             return mNetworkStats.getNetworkTotalBytes(template, start, end);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 50e03a2..0035d01 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -561,9 +561,10 @@
             final int callingUid = Binder.getCallingUid();
             final DevicePolicyManagerInternal dpmi = LocalServices.getService(
                     DevicePolicyManagerInternal.class);
-            if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
-                    || dpmi.isActiveAdminWithPolicy(callingUid,
-                            DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) {
+
+            // Device owners are also profile owners so it is enough to check for that.
+            if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) {
                 return;
             }
         }
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index 6a04688c..b5b97d6 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public boolean isValidConditionid(Uri id) {
+    public boolean isValidConditionId(Uri id) {
         return ZenModeConfig.isValidCountdownConditionId(id);
     }
 
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
new file mode 100644
index 0000000..425e222
--- /dev/null
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+
+/**
+ * Built-in zen condition provider for calendar event-based conditions.
+ */
+public class EventConditionProvider extends SystemConditionProviderService {
+    private static final String TAG = "ConditionProviders";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    public static final ComponentName COMPONENT =
+            new ComponentName("android", EventConditionProvider.class.getName());
+    private static final String NOT_SHOWN = "...";
+
+    private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
+
+    private boolean mConnected;
+    private boolean mRegistered;
+
+    public EventConditionProvider() {
+        if (DEBUG) Slog.d(TAG, "new EventConditionProvider()");
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+
+    @Override
+    public boolean isValidConditionId(Uri id) {
+        return ZenModeConfig.isValidEventConditionId(id);
+    }
+
+    @Override
+    public void dump(PrintWriter pw, DumpFilter filter) {
+        pw.println("    EventConditionProvider:");
+        pw.print("      mConnected="); pw.println(mConnected);
+        pw.print("      mRegistered="); pw.println(mRegistered);
+        pw.println("      mSubscriptions=");
+        for (Uri conditionId : mSubscriptions) {
+            pw.print("        ");
+            pw.println(conditionId);
+        }
+    }
+
+    @Override
+    public void onConnected() {
+        if (DEBUG) Slog.d(TAG, "onConnected");
+        mConnected = true;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (DEBUG) Slog.d(TAG, "onDestroy");
+        mConnected = false;
+    }
+
+    @Override
+    public void onRequestConditions(int relevance) {
+        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
+        // does not advertise conditions
+    }
+
+    @Override
+    public void onSubscribe(Uri conditionId) {
+        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
+        if (!ZenModeConfig.isValidEventConditionId(conditionId)) {
+            notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
+            return;
+        }
+        mSubscriptions.add(conditionId);
+        evaluateSubscriptions();
+    }
+
+    @Override
+    public void onUnsubscribe(Uri conditionId) {
+        if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
+        if (mSubscriptions.remove(conditionId)) {
+            evaluateSubscriptions();
+        }
+    }
+
+    @Override
+    public void attachBase(Context base) {
+        attachBaseContext(base);
+    }
+
+    @Override
+    public IConditionProvider asInterface() {
+        return (IConditionProvider) onBind(null);
+    }
+
+    private void evaluateSubscriptions() {
+        for (Uri conditionId : mSubscriptions) {
+            notifyCondition(conditionId, Condition.STATE_FALSE, "notImplemented");
+        }
+    }
+
+    private void notifyCondition(Uri conditionId, int state, String reason) {
+        if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
+                + " reason=" + reason);
+        notifyCondition(createCondition(conditionId, state));
+    }
+
+    private Condition createCondition(Uri id, int state) {
+        final String summary = NOT_SHOWN;
+        final String line1 = NOT_SHOWN;
+        final String line2 = NOT_SHOWN;
+        return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS);
+    }
+
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 9ccb2ea..b92c734 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -495,7 +495,7 @@
                                 Slog.v(TAG, getCaption() + " connection lost: " + name);
                             }
                         },
-                        Context.BIND_AUTO_CREATE,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                         new UserHandle(userid)))
                 {
                     mServicesBinding.remove(servicesBindingTag);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e106a4a..c9f5bdf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -112,6 +112,7 @@
                 + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon));
         pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.getScore());
         pw.println(prefix + "  key=" + sbn.getKey());
+        pw.println(prefix + "  seen=" + mIsSeen);
         pw.println(prefix + "  groupKey=" + getGroupKey());
         pw.println(prefix + "  contentIntent=" + notification.contentIntent);
         pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 383d56c..0912e97 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public boolean isValidConditionid(Uri id) {
+    public boolean isValidConditionId(Uri id) {
         return ZenModeConfig.isValidScheduleConditionId(id);
     }
 
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
index a217623..3282a69a 100644
--- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -32,5 +32,5 @@
     abstract public void attachBase(Context context);
     abstract public IConditionProvider asInterface();
     abstract public ComponentName getComponent();
-    abstract public boolean isValidConditionid(Uri id);
+    abstract public boolean isValidConditionId(Uri id);
 }
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 1e318ef..44fbd2d 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -115,8 +115,8 @@
         append(TYPE_UNSUBSCRIBE, uri + "," + subscribeResult(provider, e));
     }
 
-    public static void traceConfig(ZenModeConfig oldConfig, ZenModeConfig newConfig) {
-        append(TYPE_CONFIG, newConfig != null ? newConfig.toString() : null);
+    public static void traceConfig(String reason, ZenModeConfig newConfig) {
+        append(TYPE_CONFIG, reason + "," + (newConfig != null ? newConfig.toString() : null));
     }
 
     public static void traceDisableEffects(NotificationRecord record, String reason) {
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 766d6c5..fa314de 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -38,20 +38,19 @@
     private final ConditionProviders mConditionProviders;
     private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
 
-    private CountdownConditionProvider mCountdown;
-    private ScheduleConditionProvider mSchedule;
     private boolean mFirstEvaluation = true;
 
     public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
         mHelper = helper;
         mConditionProviders = conditionProviders;
         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) {
-            mCountdown = new CountdownConditionProvider();
-            mConditionProviders.addSystemProvider(mCountdown);
+            mConditionProviders.addSystemProvider(new CountdownConditionProvider());
         }
         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) {
-            mSchedule = new ScheduleConditionProvider();
-            mConditionProviders.addSystemProvider(mSchedule);
+            mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
+        }
+        if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
+            mConditionProviders.addSystemProvider(new EventConditionProvider());
         }
         mConditionProviders.setCallback(this);
     }
@@ -128,7 +127,7 @@
         final Uri id = rule.conditionId;
         boolean isSystemCondition = false;
         for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
-            if (sp.isValidConditionid(id)) {
+            if (sp.isValidConditionId(id)) {
                 mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
                 rule.component = sp.getComponent();
                 isSystemCondition = true;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9cb8af5..83f0bcfc 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -17,6 +17,7 @@
 package com.android.server.notification;
 
 import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_MEDIA;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
 
@@ -262,8 +263,8 @@
         }
         mConditions.evaluateConfig(config);  // may modify config
         if (config.equals(mConfig)) return true;
-        if (DEBUG) Log.d(TAG, "setConfig reason=" + reason);
-        ZenLog.traceConfig(mConfig, config);
+        if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
+        ZenLog.traceConfig(reason, config);
         final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
                 getNotificationPolicy(config));
         mConfig = config;
@@ -329,9 +330,10 @@
                 || mEffectsSuppressed;
         applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
 
-        // alarm restrictions
-        final boolean muteAlarms = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
-        applyRestrictions(muteAlarms, USAGE_ALARM);
+        // alarm/media restrictions
+        final boolean zenNone = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        applyRestrictions(zenNone, USAGE_ALARM);
+        applyRestrictions(zenNone, USAGE_MEDIA);
     }
 
     private void applyRestrictions(boolean mute, int usage) {
@@ -590,6 +592,11 @@
                     ringerModeInternal, ringerModeInternalOut);
             return ringerModeInternalOut;
         }
+
+        @Override
+        public boolean canVolumeDownEnterSilent() {
+            return mZenMode == Global.ZEN_MODE_OFF;
+        }
     }
 
     private final class SettingsObserver extends ContentObserver {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 0f3b4e6b..fb98d94 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -264,9 +264,9 @@
         return mInstaller.execute(builder.toString());
     }
 
-    public int moveUserDataDirs(String fromUuid, String toUuid, String packageName, int appId,
-            String seinfo) {
-        StringBuilder builder = new StringBuilder("mvuserdata");
+    public int moveCompleteApp(String fromUuid, String toUuid, String packageName,
+            String dataAppName, int appId, String seinfo) {
+        StringBuilder builder = new StringBuilder("mvcompleteapp");
         builder.append(' ');
         builder.append(escapeNull(fromUuid));
         builder.append(' ');
@@ -274,6 +274,8 @@
         builder.append(' ');
         builder.append(packageName);
         builder.append(' ');
+        builder.append(dataAppName);
+        builder.append(' ');
         builder.append(appId);
         builder.append(' ');
         builder.append(seinfo);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a406175..09096ff 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -969,8 +969,11 @@
         public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                 Bundle extras) {
             if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
+                boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
                 Notification notification = buildSuccessNotification(mContext,
-                        mContext.getResources().getString(R.string.package_installed_device_owner),
+                        mContext.getResources()
+                                .getString(update ? R.string.package_updated_device_owner :
+                                        R.string.package_installed_device_owner),
                         basePackageName,
                         mUserId);
                 if (notification != null) {
@@ -980,6 +983,7 @@
                 }
             }
             final Intent fillIn = new Intent();
+            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
             fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
                     PackageManager.installStatusToPublicStatus(returnCode));
@@ -1030,6 +1034,7 @@
                         R.color.system_notification_accent_color))
                 .setContentTitle(packageLabel)
                 .setContentText(contentText)
+                .setStyle(new Notification.BigTextStyle().bigText(contentText))
                 .setLargeIcon(packageIcon)
                 .build();
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f087c33..9ad594e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -49,6 +49,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -154,6 +155,7 @@
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.system.ErrnoException;
@@ -169,6 +171,7 @@
 import android.util.ExceptionUtils;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.util.MathUtils;
 import android.util.PrintStreamPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -239,6 +242,8 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
@@ -297,7 +302,6 @@
     static final int SCAN_BOOTING = 1<<8;
     static final int SCAN_TRUSTED_OVERLAY = 1<<9;
     static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
-    static final int SCAN_REPLACING = 1<<11;
     static final int SCAN_REQUIRE_KNOWN = 1<<12;
 
     static final int REMOVE_CHATTY = 1<<16;
@@ -1557,6 +1561,11 @@
                 }
             }
         }
+
+        @Override
+        public void onVolumeForgotten(String fsUuid) {
+            // TODO: remove all packages hosted on this uuid
+        }
     };
 
     private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId) {
@@ -1596,6 +1605,12 @@
                         res.origPackage);
                 break;
             }
+            case PackageManager.INSTALL_SUCCEEDED: {
+                extras = new Bundle();
+                extras.putBoolean(Intent.EXTRA_REPLACING,
+                        res.removedInfo != null && res.removedInfo.removedPackage != null);
+                break;
+            }
         }
         return extras;
     }
@@ -2274,6 +2289,13 @@
                 }
                 continue;
             }
+            if (!pkg.isSystemApp()) {
+                if (logging) {
+                    Slog.d(TAG, "No priming domain verifications for a non system package : " +
+                            packageName);
+                }
+                continue;
+            }
             for (PackageParser.Activity a : pkg.activities) {
                 for (ActivityIntentInfo filter : a.intents) {
                     if (hasValidDomains(filter, false)) {
@@ -2281,7 +2303,7 @@
                     }
                 }
             }
-            if (allHosts.size() > 0) {
+            if (allHosts.size() == 0) {
                 allHosts.add("*");
             }
             IntentFilterVerificationInfo ivi =
@@ -2366,6 +2388,18 @@
     }
 
     @Override
+    public boolean isPackageFrozen(String packageName) {
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps != null) {
+                return ps.frozen;
+            }
+        }
+        Slog.w(TAG, "Package " + packageName + " is missing; assuming frozen");
+        return true;
+    }
+
+    @Override
     public boolean isPackageAvailable(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return false;
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "is package available");
@@ -3921,25 +3955,26 @@
                 // Check for results that need to skip the current profile.
                 ResolveInfo resolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                         resolvedType, flags, userId);
-                if (resolveInfo != null) {
+                if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) {
                     List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                     result.add(resolveInfo);
                     return filterIfNotPrimaryUser(result, userId);
                 }
-                // Check for cross profile results.
-                resolveInfo = queryCrossProfileIntents(
-                        matchingFilters, intent, resolvedType, flags, userId);
 
                 // Check for results in the current profile.
                 List<ResolveInfo> result = mActivities.queryIntent(
                         intent, resolvedType, flags, userId);
-                if (resolveInfo != null) {
+
+                // Check for cross profile results.
+                resolveInfo = queryCrossProfileIntents(
+                        matchingFilters, intent, resolvedType, flags, userId);
+                if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) {
                     result.add(resolveInfo);
                     Collections.sort(result, mResolvePrioritySorter);
                 }
                 result = filterIfNotPrimaryUser(result, userId);
                 if (result.size() > 1 && hasWebURI(intent)) {
-                    return filterCandidatesWithDomainPreferedActivitiesLPr(result);
+                    return filterCandidatesWithDomainPreferedActivitiesLPr(flags, result);
                 }
                 return result;
             }
@@ -3954,6 +3989,16 @@
         }
     }
 
+    private boolean isUserEnabled(int userId) {
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            UserInfo userInfo = sUserManager.getUserInfo(userId);
+            return userInfo != null && userInfo.isEnabled();
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     /**
      * Filter out activities with primaryUserOnly flag set, when current user is not the owner.
      *
@@ -3984,7 +4029,7 @@
     }
 
     private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPr(
-            List<ResolveInfo> candidates) {
+            int flags, List<ResolveInfo> candidates) {
         if (DEBUG_PREFERRED) {
             Slog.v("TAG", "Filtering results with prefered activities. Candidates count: " +
                     candidates.size());
@@ -4004,6 +4049,11 @@
                 String packageName = info.activityInfo.packageName;
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null) {
+                    // Add to the special match all list (Browser use case)
+                    if (info.handleAllWebDataURI) {
+                        matchAllList.add(info);
+                        continue;
+                    }
                     // Try to get the status from User settings first
                     int status = getDomainVerificationStatusLPr(ps, userId);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
@@ -4013,10 +4063,6 @@
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
                         undefinedList.add(info);
                     }
-                    // Add to the special match all list (Browser use case)
-                    if (info.handleAllWebDataURI) {
-                        matchAllList.add(info);
-                    }
                 }
             }
             // If there is nothing selected, add all candidates and remove the ones that the User
@@ -4031,7 +4077,30 @@
             result.removeAll(matchAllList);
             if (result.size() == 0) {
                 result.addAll(undefinedList);
-                result.addAll(matchAllList);
+                if ((flags & MATCH_ALL) != 0) {
+                    result.addAll(matchAllList);
+                } else {
+                    // Try to add the Default Browser if we can
+                    final String defaultBrowserPackageName = getDefaultBrowserPackageName(
+                            UserHandle.myUserId());
+                    if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
+                        boolean defaultBrowserFound = false;
+                        final int browserCount = matchAllList.size();
+                        for (int n=0; n<browserCount; n++) {
+                            ResolveInfo browser = matchAllList.get(n);
+                            if (browser.activityInfo.packageName.equals(defaultBrowserPackageName)) {
+                                result.add(browser);
+                                defaultBrowserFound = true;
+                                break;
+                            }
+                        }
+                        if (!defaultBrowserFound) {
+                            result.addAll(matchAllList);
+                        }
+                    } else {
+                        result.addAll(matchAllList);
+                    }
+                }
             }
         }
         if (DEBUG_PREFERRED) {
@@ -4983,8 +5052,7 @@
                             + " better than installed " + ps.versionCode);
 
                     InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
-                            getAppDexInstructionSets(ps));
+                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
                     synchronized (mInstallLock) {
                         args.cleanUpResourcesLI();
                     }
@@ -5050,8 +5118,7 @@
                             + " reverting from " + ps.codePathString + ": new version "
                             + pkg.mVersionCode + " better than installed " + ps.versionCode);
                     InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
-                            getAppDexInstructionSets(ps));
+                            ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
                     synchronized (mInstallLock) {
                         args.cleanUpResourcesLI();
                     }
@@ -6433,14 +6500,6 @@
             }
         }
 
-        // Request the ActivityManager to kill the process(only for existing packages)
-        // so that we do not end up in a confused state while the user is still using the older
-        // version of the application while the new one gets installed.
-        if ((scanFlags & SCAN_REPLACING) != 0) {
-            killApplication(pkg.applicationInfo.packageName,
-                        pkg.applicationInfo.uid, "update pkg");
-        }
-
         // Also need to kill any apps that are dependent on the library.
         if (clientLibPkgs != null) {
             for (int i=0; i<clientLibPkgs.size(); i++) {
@@ -8441,46 +8500,53 @@
         }
     };
 
-    static final void sendPackageBroadcast(String action, String pkg,
-            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
-            int[] userIds) {
-        IActivityManager am = ActivityManagerNative.getDefault();
-        if (am != null) {
-            try {
-                if (userIds == null) {
-                    userIds = am.getRunningUserIds();
+    final void sendPackageBroadcast(final String action, final String pkg,
+            final Bundle extras, final String targetPkg, final IIntentReceiver finishedReceiver,
+            final int[] userIds) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IActivityManager am = ActivityManagerNative.getDefault();
+                    if (am == null) return;
+                    final int[] resolvedUserIds;
+                    if (userIds == null) {
+                        resolvedUserIds = am.getRunningUserIds();
+                    } else {
+                        resolvedUserIds = userIds;
+                    }
+                    for (int id : resolvedUserIds) {
+                        final Intent intent = new Intent(action,
+                                pkg != null ? Uri.fromParts("package", pkg, null) : null);
+                        if (extras != null) {
+                            intent.putExtras(extras);
+                        }
+                        if (targetPkg != null) {
+                            intent.setPackage(targetPkg);
+                        }
+                        // Modify the UID when posting to other users
+                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                        if (uid > 0 && UserHandle.getUserId(uid) != id) {
+                            uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
+                            intent.putExtra(Intent.EXTRA_UID, uid);
+                        }
+                        intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        if (DEBUG_BROADCASTS) {
+                            RuntimeException here = new RuntimeException("here");
+                            here.fillInStackTrace();
+                            Slog.d(TAG, "Sending to user " + id + ": "
+                                    + intent.toShortString(false, true, false, false)
+                                    + " " + intent.getExtras(), here);
+                        }
+                        am.broadcastIntent(null, intent, null, finishedReceiver,
+                                0, null, null, null, android.app.AppOpsManager.OP_NONE,
+                                finishedReceiver != null, false, id);
+                    }
+                } catch (RemoteException ex) {
                 }
-                for (int id : userIds) {
-                    final Intent intent = new Intent(action,
-                            pkg != null ? Uri.fromParts("package", pkg, null) : null);
-                    if (extras != null) {
-                        intent.putExtras(extras);
-                    }
-                    if (targetPkg != null) {
-                        intent.setPackage(targetPkg);
-                    }
-                    // Modify the UID when posting to other users
-                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                    if (uid > 0 && UserHandle.getUserId(uid) != id) {
-                        uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
-                        intent.putExtra(Intent.EXTRA_UID, uid);
-                    }
-                    intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                    if (DEBUG_BROADCASTS) {
-                        RuntimeException here = new RuntimeException("here");
-                        here.fillInStackTrace();
-                        Slog.d(TAG, "Sending to user " + id + ": "
-                                + intent.toShortString(false, true, false, false)
-                                + " " + intent.getExtras(), here);
-                    }
-                    am.broadcastIntent(null, intent, null, finishedReceiver,
-                            0, null, null, null, android.app.AppOpsManager.OP_NONE,
-                            finishedReceiver != null, false, id);
-                }
-            } catch (RemoteException ex) {
             }
-        }
+        });
     }
 
     /**
@@ -8607,8 +8673,8 @@
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(origin, observer, installFlags,
-                installerPackageName, null, verificationParams, user, packageAbiOverride);
+        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
+                null, verificationParams, user, packageAbiOverride);
         mHandler.sendMessage(msg);
     }
 
@@ -8626,7 +8692,7 @@
         }
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(origin, observer, params.installFlags,
+        msg.obj = new InstallParams(origin, null, observer, params.installFlags,
                 installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride);
         mHandler.sendMessage(msg);
     }
@@ -9459,8 +9525,30 @@
         }
     }
 
+    class MoveInfo {
+        final int moveId;
+        final String fromUuid;
+        final String toUuid;
+        final String packageName;
+        final String dataAppName;
+        final int appId;
+        final String seinfo;
+
+        public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
+                String dataAppName, int appId, String seinfo) {
+            this.moveId = moveId;
+            this.fromUuid = fromUuid;
+            this.toUuid = toUuid;
+            this.packageName = packageName;
+            this.dataAppName = dataAppName;
+            this.appId = appId;
+            this.seinfo = seinfo;
+        }
+    }
+
     class InstallParams extends HandlerParams {
         final OriginInfo origin;
+        final MoveInfo move;
         final IPackageInstallObserver2 observer;
         int installFlags;
         final String installerPackageName;
@@ -9470,11 +9558,12 @@
         private int mRet;
         final String packageAbiOverride;
 
-        InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
-                String installerPackageName, String volumeUuid,
+        InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
+                int installFlags, String installerPackageName, String volumeUuid,
                 VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
             super(user);
             this.origin = origin;
+            this.move = move;
             this.observer = observer;
             this.installFlags = installFlags;
             this.installerPackageName = installerPackageName;
@@ -9853,7 +9942,9 @@
     }
 
     private InstallArgs createInstallArgs(InstallParams params) {
-        if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
+        if (params.move != null) {
+            return new MoveInstallArgs(params);
+        } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
             return new AsecInstallArgs(params);
         } else {
             return new FileInstallArgs(params);
@@ -9865,7 +9956,7 @@
      * when cleaning up old installs, or used as a move source.
      */
     private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
-            String resourcePath, String nativeLibraryRoot, String[] instructionSets) {
+            String resourcePath, String[] instructionSets) {
         final boolean isInAsec;
         if (installOnExternalAsec(installFlags)) {
             /* Apps on SD card are always in ASEC containers. */
@@ -9885,14 +9976,15 @@
             return new AsecInstallArgs(codePath, instructionSets,
                     installOnExternalAsec(installFlags), installForwardLocked(installFlags));
         } else {
-            return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
-                    instructionSets);
+            return new FileInstallArgs(codePath, resourcePath, instructionSets);
         }
     }
 
     static abstract class InstallArgs {
         /** @see InstallParams#origin */
         final OriginInfo origin;
+        /** @see InstallParams#move */
+        final MoveInfo move;
 
         final IPackageInstallObserver2 observer;
         // Always refers to PackageManager flags only
@@ -9908,10 +10000,12 @@
         // if we move dex files under the common app path.
         /* nullable */ String[] instructionSets;
 
-        InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
-                String installerPackageName, String volumeUuid, ManifestDigest manifestDigest,
-                UserHandle user, String[] instructionSets, String abiOverride) {
+        InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
+                int installFlags, String installerPackageName, String volumeUuid,
+                ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+                String abiOverride) {
             this.origin = origin;
+            this.move = move;
             this.installFlags = installFlags;
             this.observer = observer;
             this.installerPackageName = installerPackageName;
@@ -9936,12 +10030,10 @@
         abstract String getCodePath();
         /** @see PackageSettingBase#resourcePathString */
         abstract String getResourcePath();
-        abstract String getLegacyNativeLibraryPath();
 
         // Need installer lock especially for dex file removal.
         abstract void cleanUpResourcesLI();
         abstract boolean doPostDeleteLI(boolean delete);
-        abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
 
         /**
          * Called before the source arguments are copied. This is used mostly
@@ -10002,7 +10094,6 @@
     class FileInstallArgs extends InstallArgs {
         private File codeFile;
         private File resourceFile;
-        private File legacyNativeLibraryPath;
 
         // Example topology:
         // /data/app/com.example/base.apk
@@ -10013,7 +10104,7 @@
 
         /** New install */
         FileInstallArgs(InstallParams params) {
-            super(params.origin, params.observer, params.installFlags,
+            super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride);
             if (isFwdLocked()) {
@@ -10022,21 +10113,11 @@
         }
 
         /** Existing install */
-        FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath,
-                String[] instructionSets) {
-            super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null);
+        FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
+            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+                    null);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
-            this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ?
-                    new File(legacyNativeLibraryPath) : null;
-        }
-
-        boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            final long sizeBytes = imcs.calculateInstalledSize(origin.file.getAbsolutePath(),
-                    isFwdLocked(), abiOverride);
-
-            final StorageManager storage = StorageManager.from(mContext);
-            return (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory()));
         }
 
         int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
@@ -10108,46 +10189,46 @@
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
                 return false;
-            } else {
-                final File targetDir = codeFile.getParentFile();
-                final File beforeCodeFile = codeFile;
-                final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
-
-                Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
-                try {
-                    Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
-                } catch (ErrnoException e) {
-                    Slog.d(TAG, "Failed to rename", e);
-                    return false;
-                }
-
-                if (!SELinux.restoreconRecursive(afterCodeFile)) {
-                    Slog.d(TAG, "Failed to restorecon");
-                    return false;
-                }
-
-                // Reflect the rename internally
-                codeFile = afterCodeFile;
-                resourceFile = afterCodeFile;
-
-                // Reflect the rename in scanned details
-                pkg.codePath = afterCodeFile.getAbsolutePath();
-                pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
-                        pkg.baseCodePath);
-                pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
-                        pkg.splitCodePaths);
-
-                // Reflect the rename in app info
-                pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
-                pkg.applicationInfo.setCodePath(pkg.codePath);
-                pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
-                pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
-                pkg.applicationInfo.setResourcePath(pkg.codePath);
-                pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
-                pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
-
-                return true;
             }
+
+            final File targetDir = codeFile.getParentFile();
+            final File beforeCodeFile = codeFile;
+            final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
+
+            Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+            try {
+                Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+            } catch (ErrnoException e) {
+                Slog.d(TAG, "Failed to rename", e);
+                return false;
+            }
+
+            if (!SELinux.restoreconRecursive(afterCodeFile)) {
+                Slog.d(TAG, "Failed to restorecon");
+                return false;
+            }
+
+            // Reflect the rename internally
+            codeFile = afterCodeFile;
+            resourceFile = afterCodeFile;
+
+            // Reflect the rename in scanned details
+            pkg.codePath = afterCodeFile.getAbsolutePath();
+            pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+                    pkg.baseCodePath);
+            pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+                    pkg.splitCodePaths);
+
+            // Reflect the rename in app info
+            pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
+            pkg.applicationInfo.setCodePath(pkg.codePath);
+            pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
+            pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
+            pkg.applicationInfo.setResourcePath(pkg.codePath);
+            pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
+            pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
+
+            return true;
         }
 
         int doPostInstall(int status, int uid) {
@@ -10167,11 +10248,6 @@
             return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
         }
 
-        @Override
-        String getLegacyNativeLibraryPath() {
-            return (legacyNativeLibraryPath != null) ? legacyNativeLibraryPath.getAbsolutePath() : null;
-        }
-
         private boolean cleanUp() {
             if (codeFile == null || !codeFile.exists()) {
                 return false;
@@ -10187,13 +10263,6 @@
                 resourceFile.delete();
             }
 
-            if (legacyNativeLibraryPath != null && !FileUtils.contains(codeFile, legacyNativeLibraryPath)) {
-                if (!FileUtils.deleteContents(legacyNativeLibraryPath)) {
-                    Slog.w(TAG, "Couldn't delete native library directory " + legacyNativeLibraryPath);
-                }
-                legacyNativeLibraryPath.delete();
-            }
-
             return true;
         }
 
@@ -10257,11 +10326,10 @@
         String cid;
         String packagePath;
         String resourcePath;
-        String legacyNativeLibraryDir;
 
         /** New install */
         AsecInstallArgs(InstallParams params) {
-            super(params.origin, params.observer, params.installFlags,
+            super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride);
         }
@@ -10269,7 +10337,7 @@
         /** Existing install */
         AsecInstallArgs(String fullCodePath, String[] instructionSets,
                         boolean isExternal, boolean isForwardLocked) {
-            super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0)
+            super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
                     instructionSets, null);
             // Hackily pretend we're still looking at a full code path
@@ -10286,7 +10354,7 @@
         }
 
         AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
-            super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
+            super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
                     instructionSets, null);
             this.cid = cid;
@@ -10297,21 +10365,6 @@
             cid = mInstallerService.allocateExternalStageCidLegacy();
         }
 
-        boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            final long sizeBytes = imcs.calculateInstalledSize(packagePath, isFwdLocked(),
-                    abiOverride);
-
-            final File target;
-            if (isExternalAsec()) {
-                target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory();
-            } else {
-                target = Environment.getDataDirectory();
-            }
-
-            final StorageManager storage = StorageManager.from(mContext);
-            return (sizeBytes <= storage.getStorageBytesUntilLow(target));
-        }
-
         int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
             if (origin.staged) {
                 Slog.d(TAG, origin.cid + " already staged; skipping copy");
@@ -10352,11 +10405,6 @@
             return resourcePath;
         }
 
-        @Override
-        String getLegacyNativeLibraryPath() {
-            return legacyNativeLibraryDir;
-        }
-
         int doPreInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 // Destroy container
@@ -10455,8 +10503,6 @@
                 packagePath = mountFile.getAbsolutePath();
                 resourcePath = packagePath;
             }
-
-            legacyNativeLibraryDir = new File(mountFile, LIB_DIR_NAME).getAbsolutePath();
         }
 
         int doPostInstall(int status, int uid) {
@@ -10518,8 +10564,6 @@
             removeDexFiles(allCodePaths, instructionSets);
         }
 
-
-
         String getPackageName() {
             return getAsecPackageName(cid);
         }
@@ -10568,6 +10612,108 @@
         }
     }
 
+    /**
+     * Logic to handle movement of existing installed applications.
+     */
+    class MoveInstallArgs extends InstallArgs {
+        private File codeFile;
+        private File resourceFile;
+
+        /** New install */
+        MoveInstallArgs(InstallParams params) {
+            super(params.origin, params.move, params.observer, params.installFlags,
+                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.getUser(), null /* instruction sets */, params.packageAbiOverride);
+        }
+
+        int copyApk(IMediaContainerService imcs, boolean temp) {
+            Slog.d(TAG, "Moving " + move.packageName + " from " + move.fromUuid + " to "
+                    + move.toUuid);
+            synchronized (mInstaller) {
+                if (mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
+                        move.dataAppName, move.appId, move.seinfo) != 0) {
+                    return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                }
+            }
+
+            codeFile = new File(Environment.getDataAppDirectory(move.toUuid), move.dataAppName);
+            resourceFile = codeFile;
+            Slog.d(TAG, "codeFile after move is " + codeFile);
+
+            return PackageManager.INSTALL_SUCCEEDED;
+        }
+
+        int doPreInstall(int status) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+            }
+            return status;
+        }
+
+        boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+                return false;
+            }
+
+            // Reflect the move in app info
+            pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
+            pkg.applicationInfo.setCodePath(pkg.codePath);
+            pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
+            pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
+            pkg.applicationInfo.setResourcePath(pkg.codePath);
+            pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
+            pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
+
+            return true;
+        }
+
+        int doPostInstall(int status, int uid) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+            }
+            return status;
+        }
+
+        @Override
+        String getCodePath() {
+            return (codeFile != null) ? codeFile.getAbsolutePath() : null;
+        }
+
+        @Override
+        String getResourcePath() {
+            return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
+        }
+
+        private boolean cleanUp() {
+            if (codeFile == null || !codeFile.exists()) {
+                return false;
+            }
+
+            if (codeFile.isDirectory()) {
+                mInstaller.rmPackageDir(codeFile.getAbsolutePath());
+            } else {
+                codeFile.delete();
+            }
+
+            if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
+                resourceFile.delete();
+            }
+
+            return true;
+        }
+
+        void cleanUpResourcesLI() {
+            cleanUp();
+        }
+
+        boolean doPostDeleteLI(boolean delete) {
+            // XXX err, shouldn't we respect the delete flag?
+            cleanUpResourcesLI();
+            return true;
+        }
+    }
+
     static String getAsecPackageName(String packageCid) {
         int idx = packageCid.lastIndexOf("-");
         if (idx == -1) {
@@ -10748,16 +10894,17 @@
     private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
             UserHandle user, String installerPackageName, String volumeUuid,
             PackageInstalledInfo res) {
-        PackageParser.Package oldPackage;
-        String pkgName = pkg.packageName;
-        int[] allUsers;
-        boolean[] perUserInstalled;
+        final PackageParser.Package oldPackage;
+        final String pkgName = pkg.packageName;
+        final int[] allUsers;
+        final boolean[] perUserInstalled;
+        final boolean weFroze;
 
         // First find the old package info and check signatures
         synchronized(mPackages) {
             oldPackage = mPackages.get(pkgName);
             if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
-            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final PackageSetting ps = mSettings.mPackages.get(pkgName);
             if (ps == null || !ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) {
                 // default to original signature matching
                 if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
@@ -10781,15 +10928,35 @@
             for (int i = 0; i < allUsers.length; i++) {
                 perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
             }
+
+            // Mark the app as frozen to prevent launching during the upgrade
+            // process, and then kill all running instances
+            if (!ps.frozen) {
+                ps.frozen = true;
+                weFroze = true;
+            } else {
+                weFroze = false;
+            }
         }
 
-        boolean sysPkg = (isSystemApp(oldPackage));
-        if (sysPkg) {
-            replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
-        } else {
-            replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
+        // Now that we're guarded by frozen state, kill app during upgrade
+        killApplication(pkgName, oldPackage.applicationInfo.uid, "replace pkg");
+
+        try {
+            boolean sysPkg = (isSystemApp(oldPackage));
+            if (sysPkg) {
+                replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
+                        user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
+            } else {
+                replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
+                        user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
+            }
+        } finally {
+            // Regardless of success or failure of upgrade steps above, always
+            // unfreeze the package if we froze it
+            if (weFroze) {
+                unfreezePackage(pkgName);
+            }
         }
     }
 
@@ -10919,8 +11086,6 @@
             }
         }
 
-        killApplication(packageName, oldPkg.applicationInfo.uid, "replace sys pkg");
-
         res.removedInfo.uid = oldPkg.applicationInfo.uid;
         res.removedInfo.removedPackage = packageName;
         // Remove existing system package
@@ -10935,7 +11100,6 @@
                 res.removedInfo.args = createInstallArgsForExisting(0,
                         deletedPackage.applicationInfo.getCodePath(),
                         deletedPackage.applicationInfo.getResourcePath(),
-                        deletedPackage.applicationInfo.nativeLibraryRootDir,
                         getAppDexInstructionSets(deletedPackage.applicationInfo));
             } else {
                 res.removedInfo.args = null;
@@ -11243,8 +11407,10 @@
             return;
         }
 
-        // If app directory is not writable, dexopt will be called after the rename
-        if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
+        if (args.move != null) {
+            // We did an in-place move, so dex is ready to roll
+            scanFlags |= SCAN_NO_DEX;
+        } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
             // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
             scanFlags |= SCAN_NO_DEX;
             // Run dexopt before old package gets removed, to minimize time when app is unavailable
@@ -11265,7 +11431,7 @@
         startIntentFilterVerifications(args.user.getIdentifier(), pkg);
 
         if (replace) {
-            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
+            replacePackageLI(pkg, parseFlags, scanFlags, args.user,
                     installerPackageName, volumeUuid, res);
         } else {
             installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
@@ -11331,10 +11497,16 @@
                                 verifierUid, userId, verificationId, filter, packageName);
                         count++;
                     } else if (!needsFilterVerification) {
-                        Slog.d(TAG, "No verification needed for IntentFilter:"
-                                + filter.toString());
+                        Slog.d(TAG, "No verification needed for IntentFilter:" + filter.toString());
                         if (hasValidDomains(filter)) {
-                            allHosts.addAll(filter.getHostsList());
+                            ArrayList<String> hosts = filter.getHostsList();
+                            if (hosts.size() > 0) {
+                                allHosts.addAll(hosts);
+                            } else {
+                                if (allHosts.isEmpty()) {
+                                    allHosts.add("*");
+                                }
+                            }
                         }
                     } else {
                         Slog.d(TAG, "Verification already done for IntentFilter:"
@@ -11621,7 +11793,7 @@
         return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
     }
 
-    static class PackageRemovedInfo {
+    class PackageRemovedInfo {
         String removedPackage;
         int uid = -1;
         int removedAppId = -1;
@@ -11866,8 +12038,7 @@
         // Delete application code and resources
         if (deleteCodeAndResources && (outInfo != null)) {
             outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
-                    ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
-                    getAppDexInstructionSets(ps));
+                    ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
             if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
         }
         return true;
@@ -13036,8 +13207,8 @@
         enforceCrossUserPermission(uid, userId, true, true, "stop package");
         // writer
         synchronized (mPackages) {
-            if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
-                    uid, userId)) {
+            if (mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
+                    allowedByPermission, uid, userId)) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
         }
@@ -14097,17 +14268,16 @@
     private void loadPrivatePackages(VolumeInfo vol) {
         final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
+        synchronized (mInstallLock) {
         synchronized (mPackages) {
             final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
             for (PackageSetting ps : packages) {
-                synchronized (mInstallLock) {
-                    final PackageParser.Package pkg;
-                    try {
-                        pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
-                        loaded.add(pkg.applicationInfo);
-                    } catch (PackageManagerException e) {
-                        Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
-                    }
+                final PackageParser.Package pkg;
+                try {
+                    pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
+                    loaded.add(pkg.applicationInfo);
+                } catch (PackageManagerException e) {
+                    Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
                 }
             }
 
@@ -14115,6 +14285,7 @@
 
             mSettings.writeLPr();
         }
+        }
 
         Slog.d(TAG, "Loaded packages " + loaded);
         sendResourcesChangedBroadcast(true, false, loaded, null);
@@ -14122,29 +14293,39 @@
 
     private void unloadPrivatePackages(VolumeInfo vol) {
         final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+        synchronized (mInstallLock) {
         synchronized (mPackages) {
             final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
             for (PackageSetting ps : packages) {
                 if (ps.pkg == null) continue;
-                synchronized (mInstallLock) {
-                    final ApplicationInfo info = ps.pkg.applicationInfo;
-                    final PackageRemovedInfo outInfo = new PackageRemovedInfo();
-                    if (deletePackageLI(ps.name, null, false, null, null,
-                            PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
-                        unloaded.add(info);
-                    } else {
-                        Slog.w(TAG, "Failed to unload " + ps.codePath);
-                    }
+
+                final ApplicationInfo info = ps.pkg.applicationInfo;
+                final PackageRemovedInfo outInfo = new PackageRemovedInfo();
+                if (deletePackageLI(ps.name, null, false, null, null,
+                        PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
+                    unloaded.add(info);
+                } else {
+                    Slog.w(TAG, "Failed to unload " + ps.codePath);
                 }
             }
 
             mSettings.writeLPr();
         }
+        }
 
         Slog.d(TAG, "Unloaded packages " + unloaded);
         sendResourcesChangedBroadcast(false, false, unloaded, null);
     }
 
+    private void unfreezePackage(String packageName) {
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps != null) {
+                ps.frozen = false;
+            }
+        }
+    }
+
     @Override
     public int movePackage(final String packageName, final String volumeUuid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
@@ -14154,7 +14335,8 @@
             movePackageInternal(packageName, volumeUuid, moveId);
         } catch (PackageManagerException e) {
             Slog.d(TAG, "Failed to move " + packageName, e);
-            mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INTERNAL_ERROR);
+            mMoveCallbacks.notifyStatusChanged(moveId,
+                    PackageManager.MOVE_FAILED_INTERNAL_ERROR);
         }
         return moveId;
     }
@@ -14162,6 +14344,7 @@
     private void movePackageInternal(final String packageName, final String volumeUuid,
             final int moveId) throws PackageManagerException {
         final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
         final PackageManager pm = mContext.getPackageManager();
 
         final boolean currentAsec;
@@ -14171,6 +14354,7 @@
         final String packageAbiOverride;
         final int appId;
         final String seinfo;
+        final String label;
 
         // reader
         synchronized (mPackages) {
@@ -14183,17 +14367,25 @@
             if (pkg.applicationInfo.isSystemApp()) {
                 throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
                         "Cannot move system application");
-            } else if (pkg.mOperationPending) {
-                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
-                        "Attempt to move package which has pending operations");
             }
 
-            // TODO: yell if already in desired location
+            if (Objects.equals(ps.volumeUuid, volumeUuid)) {
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Package already moved to " + volumeUuid);
+            }
 
-            mMoveCallbacks.notifyStarted(moveId,
-                    String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)));
+            final File probe = new File(pkg.codePath);
+            final File probeOat = new File(probe, "oat");
+            if (!probe.isDirectory() || !probeOat.isDirectory()) {
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Move only supported for modern cluster style installs");
+            }
 
-            pkg.mOperationPending = true;
+            if (ps.frozen) {
+                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+                        "Failed to move already frozen package");
+            }
+            ps.frozen = true;
 
             currentAsec = pkg.applicationInfo.isForwardLocked()
                     || pkg.applicationInfo.isExternalAsec();
@@ -14203,22 +14395,34 @@
             packageAbiOverride = ps.cpuAbiOverrideString;
             appId = UserHandle.getAppId(pkg.applicationInfo.uid);
             seinfo = pkg.applicationInfo.seinfo;
+            label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
         }
 
+        // Now that we're guarded by frozen state, kill app during move
+        killApplication(packageName, appId, "move pkg");
+
+        final Bundle extras = new Bundle();
+        extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+        extras.putString(Intent.EXTRA_TITLE, label);
+        mMoveCallbacks.notifyCreated(moveId, extras);
+
         int installFlags;
-        final boolean moveData;
+        final boolean moveCompleteApp;
+        final File measurePath;
 
         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
             installFlags = INSTALL_INTERNAL;
-            moveData = !currentAsec;
+            moveCompleteApp = !currentAsec;
+            measurePath = Environment.getDataAppDirectory(volumeUuid);
         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
             installFlags = INSTALL_EXTERNAL;
-            moveData = false;
+            moveCompleteApp = false;
+            measurePath = storage.getPrimaryPhysicalVolume().getPath();
         } else {
-            final StorageManager storage = mContext.getSystemService(StorageManager.class);
             final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid);
             if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE
                     || !volume.isMountedWritable()) {
+                unfreezePackage(packageName);
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
                         "Move location not mounted private volume");
             }
@@ -14226,32 +14430,38 @@
             Preconditions.checkState(!currentAsec);
 
             installFlags = INSTALL_INTERNAL;
-            moveData = true;
+            moveCompleteApp = true;
+            measurePath = Environment.getDataAppDirectory(volumeUuid);
         }
 
-        Slog.d(TAG, "Moving " + packageName + " from " + currentVolumeUuid + " to " + volumeUuid);
-        mMoveCallbacks.notifyStatusChanged(moveId, 10, -1);
-
-        if (moveData) {
-            synchronized (mInstallLock) {
-                // TODO: split this into separate copy and delete operations
-                if (mInstaller.moveUserDataDirs(currentVolumeUuid, volumeUuid, packageName, appId,
-                        seinfo) != 0) {
-                    synchronized (mPackages) {
-                        final PackageParser.Package pkg = mPackages.get(packageName);
-                        if (pkg != null) {
-                            pkg.mOperationPending = false;
-                        }
-                    }
-
-                    throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                            "Failed to move private data");
-                }
+        final PackageStats stats = new PackageStats(null, -1);
+        synchronized (mInstaller) {
+            if (!getPackageSizeInfoLI(packageName, -1, stats)) {
+                unfreezePackage(packageName);
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Failed to measure package size");
             }
         }
 
-        mMoveCallbacks.notifyStatusChanged(moveId, 50);
+        Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size " + stats.dataSize);
 
+        final long startFreeBytes = measurePath.getFreeSpace();
+        final long sizeBytes;
+        if (moveCompleteApp) {
+            sizeBytes = stats.codeSize + stats.dataSize;
+        } else {
+            sizeBytes = stats.codeSize;
+        }
+
+        if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) {
+            unfreezePackage(packageName);
+            throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                    "Not enough free space to move");
+        }
+
+        mMoveCallbacks.notifyStatusChanged(moveId, 10);
+
+        final CountDownLatch installedLatch = new CountDownLatch(1);
         final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
             @Override
             public void onUserActionRequired(Intent intent) throws RemoteException {
@@ -14264,15 +14474,11 @@
                 Slog.d(TAG, "Install result for move: "
                         + PackageManager.installStatusToString(returnCode, msg));
 
-                // We usually have a new package now after the install, but if
-                // we failed we need to clear the pending flag on the original
-                // package object.
-                synchronized (mPackages) {
-                    final PackageParser.Package pkg = mPackages.get(packageName);
-                    if (pkg != null) {
-                        pkg.mOperationPending = false;
-                    }
-                }
+                installedLatch.countDown();
+
+                // Regardless of success or failure of the move operation,
+                // always unfreeze the package
+                unfreezePackage(packageName);
 
                 final int status = PackageManager.installStatusToPublicStatus(returnCode);
                 switch (status) {
@@ -14292,13 +14498,40 @@
             }
         };
 
-        // Treat a move like reinstalling an existing app, which ensures that we
-        // process everythign uniformly, like unpacking native libraries.
+        final MoveInfo move;
+        if (moveCompleteApp) {
+            // Kick off a thread to report progress estimates
+            new Thread() {
+                @Override
+                public void run() {
+                    while (true) {
+                        try {
+                            if (installedLatch.await(1, TimeUnit.SECONDS)) {
+                                break;
+                            }
+                        } catch (InterruptedException ignored) {
+                        }
+
+                        final long deltaFreeBytes = startFreeBytes - measurePath.getFreeSpace();
+                        final int progress = 10 + (int) MathUtils.constrain(
+                                ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
+                        mMoveCallbacks.notifyStatusChanged(moveId, progress);
+                    }
+                }
+            }.start();
+
+            final String dataAppName = codeFile.getName();
+            move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
+                    dataAppName, appId, seinfo);
+        } else {
+            move = null;
+        }
+
         installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
-        msg.obj = new InstallParams(origin, installObserver, installFlags,
+        msg.obj = new InstallParams(origin, move, installObserver, installFlags,
                 installerPackageName, volumeUuid, null, user, packageAbiOverride);
         mHandler.sendMessage(msg);
     }
@@ -14308,9 +14541,13 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
 
         final int realMoveId = mNextMoveId.getAndIncrement();
+        final Bundle extras = new Bundle();
+        extras.putString(VolumeRecord.EXTRA_FS_UUID, volumeUuid);
+        mMoveCallbacks.notifyCreated(realMoveId, extras);
+
         final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
             @Override
-            public void onStarted(int moveId, String title) {
+            public void onCreated(int moveId, Bundle extras) {
                 // Ignored
             }
 
@@ -14671,7 +14908,7 @@
     }
 
     private static class MoveCallbacks extends Handler {
-        private static final int MSG_STARTED = 1;
+        private static final int MSG_CREATED = 1;
         private static final int MSG_STATUS_CHANGED = 2;
 
         private final RemoteCallbackList<IPackageMoveObserver>
@@ -14709,8 +14946,8 @@
         private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
                 throws RemoteException {
             switch (what) {
-                case MSG_STARTED: {
-                    callback.onStarted(args.argi1, (String) args.arg2);
+                case MSG_CREATED: {
+                    callback.onCreated(args.argi1, (Bundle) args.arg2);
                     break;
                 }
                 case MSG_STATUS_CHANGED: {
@@ -14720,13 +14957,13 @@
             }
         }
 
-        private void notifyStarted(int moveId, String title) {
-            Slog.v(TAG, "Move " + moveId + " started with title " + title);
+        private void notifyCreated(int moveId, Bundle extras) {
+            Slog.v(TAG, "Move " + moveId + " created " + extras.toString());
 
             final SomeArgs args = SomeArgs.obtain();
             args.argi1 = moveId;
-            args.arg2 = title;
-            obtainMessage(MSG_STARTED, args).sendToTarget();
+            args.arg2 = extras;
+            obtainMessage(MSG_CREATED, args).sendToTarget();
         }
 
         private void notifyStatusChanged(int moveId, int status) {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 5429517..f62c00c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -108,6 +108,13 @@
 
     int installStatus = PKG_INSTALL_COMPLETE;
 
+    /**
+     * Non-persisted value indicating this package has been temporarily frozen,
+     * usually during a critical section of the package update pipeline. The
+     * platform will refuse to launch packages in a frozen state.
+     */
+    boolean frozen = false;
+
     PackageSettingBase origPackage;
 
     /** Package name of the app that installed this package */
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 252c16a..7cf7c7c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3603,8 +3603,8 @@
         return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
     }
 
-    boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
-            boolean allowedByPermission, int uid, int userId) {
+    boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName,
+            boolean stopped, boolean allowedByPermission, int uid, int userId) {
         int appId = UserHandle.getAppId(uid);
         final PackageSetting pkgSetting = mPackages.get(packageName);
         if (pkgSetting == null) {
@@ -3628,7 +3628,7 @@
             // pkgSetting.pkg.mSetStopped = stopped;
             if (pkgSetting.getNotLaunched(userId)) {
                 if (pkgSetting.installerPackageName != null) {
-                    PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
+                    yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                             pkgSetting.name, null,
                             pkgSetting.installerPackageName, null, new int[] {userId});
                 }
@@ -3759,6 +3759,10 @@
             pw.print(Integer.toHexString(System.identityHashCode(ps)));
             pw.println("):");
 
+        if (ps.frozen) {
+            pw.print(prefix); pw.println("  FROZEN!");
+        }
+
         if (ps.realName != null) {
             pw.print(prefix); pw.print("  compat name=");
             pw.println(ps.name);
@@ -3790,9 +3794,6 @@
             pw.print(prefix); pw.print("  priavateFlags="); printFlags(pw,
                     ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
             pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
-            if (ps.pkg.mOperationPending) {
-                pw.print(prefix); pw.println("  mOperationPending=true");
-            }
             pw.print(prefix); pw.print("  supportsScreens=[");
             boolean first = true;
             if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5536d4d..adc3a7d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -285,6 +285,9 @@
     // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
     long[] mSafeModeEnabledVibePattern;
 
+    // Vibrator pattern for haptic feedback of a stylus button press.
+    long[] mStylusButtonPressVibePattern;
+
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
@@ -1436,6 +1439,8 @@
                 com.android.internal.R.array.config_safeModeDisabledVibePattern);
         mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_safeModeEnabledVibePattern);
+        mStylusButtonPressVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_stylusButtonPressVibePattern);
 
         mScreenshotChordEnabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableScreenshotChord);
@@ -6164,6 +6169,9 @@
             case HapticFeedbackConstants.SAFE_MODE_ENABLED:
                 pattern = mSafeModeEnabledVibePattern;
                 break;
+            case HapticFeedbackConstants.STYLUS_BUTTON_PRESS:
+                pattern = mStylusButtonPressVibePattern;
+                break;
             default:
                 return false;
         }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 926090e..01c110f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -41,11 +41,13 @@
     private volatile boolean mSimSecure;
     private volatile boolean mInputRestricted;
 
+    private int mCurrentUserId;
+
     private final LockPatternUtils mLockPatternUtils;
 
     public KeyguardStateMonitor(Context context, IKeyguardService service) {
         mLockPatternUtils = new LockPatternUtils(context);
-        mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
+        mCurrentUserId = ActivityManager.getCurrentUser();
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -58,7 +60,7 @@
     }
 
     public boolean isSecure() {
-        return mLockPatternUtils.isSecure() || mSimSecure;
+        return mLockPatternUtils.isSecure(getCurrentUser()) || mSimSecure;
     }
 
     public boolean isInputRestricted() {
@@ -75,8 +77,12 @@
         mSimSecure = simSecure;
     }
 
-    public void setCurrentUser(int userId) {
-        mLockPatternUtils.setCurrentUser(userId);
+    public synchronized void setCurrentUser(int userId) {
+        mCurrentUserId = userId;
+    }
+
+    private synchronized int getCurrentUser() {
+        return mCurrentUserId;
     }
 
     @Override // Binder interface
diff --git a/services/core/java/com/android/server/power/DeviceIdleController.java b/services/core/java/com/android/server/power/DeviceIdleController.java
deleted file mode 100644
index 6b29b9a..0000000
--- a/services/core/java/com/android/server/power/DeviceIdleController.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.power;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.TriggerEvent;
-import android.hardware.TriggerEventListener;
-import android.hardware.display.DisplayManager;
-import android.net.INetworkPolicyManager;
-import android.os.Binder;
-import android.os.PowerManager;
-import android.os.PowerManagerInternal;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.TimeUtils;
-import android.view.Display;
-import com.android.internal.app.IBatteryStats;
-import com.android.server.SystemService;
-import com.android.server.am.BatteryStatsService;
-import com.android.server.EventLogTags;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Keeps track of device idleness and drives low power mode based on that.
- */
-public class DeviceIdleController extends SystemService {
-    private static final String TAG = "DeviceIdleController";
-
-    private static final String ACTION_STEP_IDLE_STATE =
-            "com.android.server.device_idle.STEP_IDLE_STATE";
-
-    // TODO: These need to be moved to system settings.
-
-    /**
-     * This is the time, after becoming inactive, at which we start looking at the
-     * motion sensor to determine if the device is being left alone.  We don't do this
-     * immediately after going inactive just because we don't want to be continually running
-     * the significant motion sensor whenever the screen is off.
-     */
-    private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
-    /**
-     * This is the time, after seeing motion, that we wait after becoming inactive from
-     * that until we start looking for motion again.
-     */
-    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L;
-    /**
-     * This is the time, after the inactive timeout elapses, that we will wait looking
-     * for significant motion until we truly consider the device to be idle.
-     */
-    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = 30*60*1000L;
-    /**
-     * This is the initial time, after being idle, that we will allow ourself to be back
-     * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
-     */
-    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
-    /**
-     * Maximum pending idle timeout (time spent running) we will be allowed to use.
-     */
-    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
-    /**
-     * Scaling factor to apply to current pending idle timeout each time we cycle through
-     * that state.
-     */
-    private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
-    /**
-     * This is the initial time that we want to sit in the idle state before waking up
-     * again to return to pending idle and allowing normal work to run.
-     */
-    private static final long DEFAULT_IDLE_TIMEOUT = 60*60*1000L;
-    /**
-     * Maximum idle duration we will be allowed to use.
-     */
-    private static final long DEFAULT_MAX_IDLE_TIMEOUT = 6*60*60*1000L;
-    /**
-     * Scaling factor to apply to current idle timeout each time we cycle through that state.
-     */
-    private static final float DEFAULT_IDLE_FACTOR = 2f;
-    /**
-     * This is the minimum time we will allow until the next upcoming alarm for us to
-     * actually go in to idle mode.
-     */
-    private static final long DEFAULT_MIN_TIME_TO_ALARM = 60*60*1000L;
-
-    private AlarmManager mAlarmManager;
-    private IBatteryStats mBatteryStats;
-    private PowerManagerInternal mLocalPowerManager;
-    private INetworkPolicyManager mNetworkPolicyManager;
-    private DisplayManager mDisplayManager;
-    private SensorManager mSensorManager;
-    private Sensor mSigMotionSensor;
-    private PendingIntent mAlarmIntent;
-    private Intent mIdleIntent;
-    private Display mCurDisplay;
-    private boolean mScreenOn;
-    private boolean mCharging;
-    private boolean mSigMotionActive;
-
-    /** Device is currently active. */
-    private static final int STATE_ACTIVE = 0;
-    /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
-    private static final int STATE_INACTIVE = 1;
-    /** Device is past the initial inactive period, and waiting for the next idle period. */
-    private static final int STATE_IDLE_PENDING = 2;
-    /** Device is in the idle state, trying to stay asleep as much as possible. */
-    private static final int STATE_IDLE = 3;
-    private static String stateToString(int state) {
-        switch (state) {
-            case STATE_ACTIVE: return "ACTIVE";
-            case STATE_INACTIVE: return "INACTIVE";
-            case STATE_IDLE_PENDING: return "IDLE_PENDING";
-            case STATE_IDLE: return "IDLE";
-            default: return Integer.toString(state);
-        }
-    }
-
-    private int mState;
-
-    private long mInactiveTimeout;
-    private long mNextAlarmTime;
-    private long mNextIdlePendingDelay;
-    private long mNextIdleDelay;
-
-    private final Binder mBinder = new Binder() {
-        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            DeviceIdleController.this.dump(fd, pw, args);
-        }
-    };
-
-    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("plugged", 0);
-                updateChargingLocked(plugged != 0);
-            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
-                synchronized (DeviceIdleController.this) {
-                    stepIdleStateLocked();
-                }
-            }
-        }
-    };
-
-    private final DisplayManager.DisplayListener mDisplayListener
-            = new DisplayManager.DisplayListener() {
-        @Override public void onDisplayAdded(int displayId) {
-        }
-
-        @Override public void onDisplayRemoved(int displayId) {
-        }
-
-        @Override public void onDisplayChanged(int displayId) {
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                synchronized (DeviceIdleController.this) {
-                    updateDisplayLocked();
-                }
-            }
-        }
-    };
-
-    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
-        @Override public void onTrigger(TriggerEvent event) {
-            synchronized (DeviceIdleController.this) {
-                significantMotionLocked();
-            }
-        }
-    };
-
-    public DeviceIdleController(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void onStart() {
-        synchronized (this) {
-            mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
-            mBatteryStats = BatteryStatsService.getService();
-            mLocalPowerManager = getLocalService(PowerManagerInternal.class);
-            mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
-                                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
-            mDisplayManager = (DisplayManager) getContext().getSystemService(
-                    Context.DISPLAY_SERVICE);
-            mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
-            mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
-
-            Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
-                    .setPackage("android")
-                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
-
-            mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-            mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-            filter.addAction(ACTION_STEP_IDLE_STATE);
-            getContext().registerReceiver(mReceiver, filter);
-
-            mDisplayManager.registerDisplayListener(mDisplayListener, null);
-
-            mScreenOn = true;
-            // Start out assuming we are charging.  If we aren't, we will at least get
-            // a battery update the next time the level drops.
-            mCharging = true;
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
-            updateDisplayLocked();
-        }
-
-        publishBinderService("deviceidle", mBinder);
-    }
-
-    void updateDisplayLocked() {
-        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
-        // We consider any situation where the display is showing something to be it on,
-        // because if there is anything shown we are going to be updating it at some
-        // frequency so can't be allowed to go into deep sleeps.
-        boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
-        if (!screenOn && mScreenOn) {
-            mScreenOn = false;
-            becomeInactiveIfAppropriateLocked();
-        } else if (screenOn) {
-            mScreenOn = true;
-            becomeActiveLocked("screen");
-        }
-    }
-
-    void updateChargingLocked(boolean charging) {
-        if (!charging && mCharging) {
-            mCharging = false;
-            becomeInactiveIfAppropriateLocked();
-        } else if (charging) {
-            mCharging = charging;
-            becomeActiveLocked("charging");
-        }
-    }
-
-    void becomeActiveLocked(String reason) {
-        if (mState != STATE_ACTIVE) {
-            EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
-            mLocalPowerManager.setDeviceIdleMode(false);
-            try {
-                mNetworkPolicyManager.setDeviceIdleMode(false);
-                mBatteryStats.noteDeviceIdleMode(false, true, false);
-            } catch (RemoteException e) {
-            }
-            if (mState == STATE_IDLE) {
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-            }
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
-            mNextIdlePendingDelay = 0;
-            mNextIdleDelay = 0;
-            cancelAlarmLocked();
-            stopMonitoringSignificantMotion();
-        }
-    }
-
-    void becomeInactiveIfAppropriateLocked() {
-        if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
-            // Screen has turned off; we are now going to become inactive and start
-            // waiting to see if we will ultimately go idle.
-            mState = STATE_INACTIVE;
-            mNextIdlePendingDelay = 0;
-            mNextIdleDelay = 0;
-            scheduleAlarmLocked(mInactiveTimeout, false);
-            EventLogTags.writeDeviceIdle(mState, "no activity");
-        }
-    }
-
-    void stepIdleStateLocked() {
-        EventLogTags.writeDeviceIdleStep();
-
-        final long now = SystemClock.elapsedRealtime();
-        if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
-            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
-            if (mState != STATE_ACTIVE) {
-                becomeActiveLocked("alarm");
-            }
-            return;
-        }
-
-        switch (mState) {
-            case STATE_INACTIVE:
-                // We have now been inactive long enough, it is time to start looking
-                // for significant motion and sleep some more while doing so.
-                startMonitoringSignificantMotion();
-                scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
-                // Reset the upcoming idle delays.
-                mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
-                mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
-                mState = STATE_IDLE_PENDING;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                break;
-            case STATE_IDLE_PENDING:
-                // We have been waiting to become idle, and now it is time!  This is the
-                // only case where we want to use a wakeup alarm, because we do want to
-                // drag the device out of its sleep state in this case to do the next
-                // scheduled work.
-                scheduleAlarmLocked(mNextIdleDelay, true);
-                mNextIdleDelay = (long)(mNextIdleDelay*DEFAULT_IDLE_FACTOR);
-                if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
-                    mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
-                }
-                mState = STATE_IDLE;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                mLocalPowerManager.setDeviceIdleMode(true);
-                try {
-                    mNetworkPolicyManager.setDeviceIdleMode(true);
-                    mBatteryStats.noteDeviceIdleMode(true, false, false);
-                } catch (RemoteException e) {
-                }
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-                break;
-            case STATE_IDLE:
-                // We have been idling long enough, now it is time to do some work.
-                scheduleAlarmLocked(mNextIdlePendingDelay, false);
-                mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
-                if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
-                    mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
-                }
-                mState = STATE_IDLE_PENDING;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                mLocalPowerManager.setDeviceIdleMode(false);
-                try {
-                    mNetworkPolicyManager.setDeviceIdleMode(false);
-                    mBatteryStats.noteDeviceIdleMode(false, false, false);
-                } catch (RemoteException e) {
-                }
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-                break;
-        }
-    }
-
-    void significantMotionLocked() {
-        // When the sensor goes off, its trigger is automatically removed.
-        mSigMotionActive = false;
-        // The device is not yet active, so we want to go back to the pending idle
-        // state to wait again for no motion.  Note that we only monitor for significant
-        // motion after moving out of the inactive state, so no need to worry about that.
-        if (mState != STATE_ACTIVE) {
-            mLocalPowerManager.setDeviceIdleMode(false);
-            try {
-                mNetworkPolicyManager.setDeviceIdleMode(false);
-                mBatteryStats.noteDeviceIdleMode(false, false, true);
-            } catch (RemoteException e) {
-            }
-            if (mState == STATE_IDLE) {
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-            }
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
-            EventLogTags.writeDeviceIdle(mState, "motion");
-            becomeInactiveIfAppropriateLocked();
-        }
-    }
-
-    void startMonitoringSignificantMotion() {
-        if (mSigMotionSensor != null && !mSigMotionActive) {
-            mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = true;
-        }
-    }
-
-    void stopMonitoringSignificantMotion() {
-        if (mSigMotionActive) {
-            mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = false;
-        }
-    }
-
-    void cancelAlarmLocked() {
-        if (mNextAlarmTime != 0) {
-            mNextAlarmTime = 0;
-            mAlarmManager.cancel(mAlarmIntent);
-        }
-    }
-
-    void scheduleAlarmLocked(long delay, boolean idleUntil) {
-        if (mSigMotionSensor == null) {
-            // If there is no significant motion sensor on this device, then we won't schedule
-            // alarms, because we can't determine if the device is not moving.  This effectively
-            // turns off normal exeuction of device idling, although it is still possible to
-            // manually poke it by pretending like the alarm is going off.
-            return;
-        }
-        mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
-        if (idleUntil) {
-            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
-        } else {
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
-        }
-    }
-
-    private void dumpHelp(PrintWriter pw) {
-        pw.println("Device idle controller (deviceidle) dump options:");
-        pw.println("  [-h] [CMD]");
-        pw.println("  -h: print this help text.");
-        pw.println("Commands:");
-        pw.println("  step");
-        pw.println("    Immediately step to next state, without waiting for alarm.");
-    }
-
-    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
-                    + " without permission " + android.Manifest.permission.DUMP);
-            return;
-        }
-
-        if (args != null) {
-            for (int i=0; i<args.length; i++) {
-                String arg = args[i];
-                if ("-h".equals(arg)) {
-                    dumpHelp(pw);
-                    return;
-                } else if ("step".equals(arg)) {
-                    synchronized (this) {
-                        stepIdleStateLocked();
-                        pw.print("Stepped to: "); pw.println(stateToString(mState));
-                    }
-                    return;
-                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
-                    pw.println("Unknown option: " + arg);
-                    dumpHelp(pw);
-                    return;
-                } else {
-                    pw.println("Unknown command: " + arg);
-                    dumpHelp(pw);
-                    return;
-                }
-            }
-        }
-
-        synchronized (this) {
-            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
-            pw.print("  mCurDisplay="); pw.println(mCurDisplay);
-            pw.print("  mScreenOn="); pw.println(mScreenOn);
-            pw.print("  mCharging="); pw.println(mCharging);
-            pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
-            pw.print("  mState="); pw.println(stateToString(mState));
-            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
-            pw.println();
-            if (mNextAlarmTime != 0) {
-                pw.print("  mNextAlarmTime=");
-                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
-                pw.println();
-            }
-            if (mNextIdlePendingDelay != 0) {
-                pw.print("  mNextIdlePendingDelay=");
-                TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
-                pw.println();
-            }
-            if (mNextIdleDelay != 0) {
-                pw.print("  mNextIdleDelay=");
-                TimeUtils.formatDuration(mNextIdleDelay, pw);
-                pw.println();
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6c8959c..f790f75 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1819,6 +1819,7 @@
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             // Determine appropriate screen brightness and auto-brightness adjustments.
+            boolean brightnessSetByUser = true;
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
             boolean autoBrightness = (mScreenBrightnessModeSetting ==
@@ -1826,6 +1827,7 @@
             if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                 screenBrightness = mScreenBrightnessOverrideFromWindowManager;
                 autoBrightness = false;
+                brightnessSetByUser = false;
             } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
                 screenBrightness = mTemporaryScreenBrightnessSettingOverride;
             } else if (isValidBrightness(mScreenBrightnessSetting)) {
@@ -1851,6 +1853,7 @@
             mDisplayPowerRequest.screenBrightness = screenBrightness;
             mDisplayPowerRequest.screenAutoBrightnessAdjustment =
                     screenAutoBrightnessAdjustment;
+            mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
             mDisplayPowerRequest.useAutoBrightness = autoBrightness;
             mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
             mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 22fee22..9abdf21 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -96,7 +96,8 @@
         TelecomServiceConnection serviceConnection = new TelecomServiceConnection();
         Intent intent = new Intent(SERVICE_ACTION);
         intent.setComponent(SERVICE_COMPONENT);
-        int flags = Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE;
+        int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
+                | Context.BIND_AUTO_CREATE;
 
         // Bind to Telecom and register the service
         if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.OWNER)) {
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index fb7d186..e5c5b2bc 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -276,7 +276,8 @@
         // Schedules a restart for when connecting times out. If the connection succeeds,
         // the restart is canceled in mCallback's onConnected.
         scheduleRestart();
-        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
+        mBound = context.bindServiceAsUser(intent, mConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, user);
         if (mBound) {
             mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
         } else {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 5972247..56816f9 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -529,7 +529,9 @@
 
             Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
             serviceState.bound = mContext.bindServiceAsUser(
-                    i, serviceState.connection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
+                    i, serviceState.connection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                    new UserHandle(userId));
         } else if (serviceState.service != null && !maintainConnection) {
             // This means that the service is already connected but its state indicates that we have
             // nothing to do with it. Then, disconnect the service.
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 54be380..755c414 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1038,7 +1038,8 @@
                             mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
                     0, null, new UserHandle(serviceUserId)));
             if (!mContext.bindServiceAsUser(intent, newConn,
-                    Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,
+                    Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
+                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     new UserHandle(serviceUserId))) {
                 String msg = "Unable to bind service: "
                         + componentName;
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index e226e3d..ba3ce36 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -84,7 +84,7 @@
         int fontSize = WindowManagerService.getPropertyInt(tokens, 1,
                 TypedValue.COMPLEX_UNIT_DIP, 20, dm);
 
-        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint = new Paint();
         mTextPaint.setTextSize(fontSize);
         mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c5bdbb0..d4b3dab 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2345,7 +2345,6 @@
 
         boolean reportNewConfig = false;
         WindowState attachedWindow = null;
-        WindowState win = null;
         long origId;
         final int type = attrs.type;
 
@@ -2482,7 +2481,7 @@
                 addToken = true;
             }
 
-            win = new WindowState(this, session, client, token,
+            WindowState win = new WindowState(this, session, client, token,
                     attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
             if (win.mDeathRecipient == null) {
                 // Client has apparently died, so there is no reason to
@@ -9941,18 +9940,20 @@
 
                     final WindowStateAnimator winAnimator = w.mWinAnimator;
 
-                    // If the window has moved due to its containing
-                    // content frame changing, then we'd like to animate
-                    // it.
-                    if (w.mHasSurface && w.shouldAnimateMove()) {
-                        // Frame has moved, containing content frame
-                        // has also moved, and we're not currently animating...
-                        // let's do something.
-                        Animation a = AnimationUtils.loadAnimation(mContext,
-                                com.android.internal.R.anim.window_move_from_decor);
-                        winAnimator.setAnimation(a);
-                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
-                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+                    // If the window has moved due to its containing content frame changing, then
+                    // notify the listeners and optionally animate it.
+                    if (w.hasMoved()) {
+                        // Frame has moved, containing content frame has also moved, and we're not
+                        // currently animating... let's do something.
+                        final int left = w.mFrame.left;
+                        final int top = w.mFrame.top;
+                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0) {
+                            Animation a = AnimationUtils.loadAnimation(mContext,
+                                    com.android.internal.R.anim.window_move_from_decor);
+                            winAnimator.setAnimation(a);
+                            winAnimator.mAnimDw = w.mLastFrame.left - left;
+                            winAnimator.mAnimDh = w.mLastFrame.top - top;
+                        }
 
                         //TODO (multidisplay): Accessibility supported only for the default display.
                         if (mAccessibilityController != null
@@ -9961,7 +9962,7 @@
                         }
 
                         try {
-                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
+                            w.mClient.moved(left, top);
                         } catch (RemoteException e) {
                         }
                     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ec70879..ad25462 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,7 +20,6 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -1081,16 +1080,14 @@
     }
 
     /**
-     * Return whether this window is wanting to have a translation
-     * animation applied to it for an in-progress move.  (Only makes
+     * Return whether this window has moved. (Only makes
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
-    boolean shouldAnimateMove() {
-        return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
-                && (mFrame.top != mLastFrame.top
+    boolean hasMoved() {
+        return mHasSurface && mContentChanged && !mExiting && !mWinAnimator.mLastHidden
+                && mService.okToDisplay() && (mFrame.top != mLastFrame.top
                         || mFrame.left != mLastFrame.left)
-                && (mAttrs.privateFlags&PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
-                && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
+                && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
     }
 
     boolean isFullscreen(int screenWidth, int screenHeight) {
@@ -1709,7 +1706,7 @@
                     pw.println(mWallpaperDisplayOffsetY);
         }
         if (mDrawLock != null) {
-            pw.println("mDrawLock=" + mDrawLock);
+            pw.print(prefix); pw.println("mDrawLock=" + mDrawLock);
         }
     }
 
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index ad1d0f5..8f4fb51 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -64,7 +64,8 @@
 static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
         jobject graphicBuffer, jobject bitmapHandle) {
 
-    SkBitmap& bitmap = *GraphicsJNI::getSkBitmap(env, bitmapHandle);
+    SkBitmap bitmap;
+    GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap);
     SkAutoLockPixels alp(bitmap);
 
     // The goal of this method is to copy the bitmap into the GraphicBuffer
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index ee50ff9..d8c172f 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -71,6 +71,7 @@
 
     char *manufacturer = usb_device_get_manufacturer_name(device);
     char *product = usb_device_get_product_name(device);
+    int version = usb_device_get_version(device);
     char *serial = usb_device_get_serial(device);
 
     jstring deviceName = env->NewStringUTF(devname);
@@ -81,7 +82,7 @@
     jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
             deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
             deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
-            manufacturerName, productName, serialNumber);
+            manufacturerName, productName, version, serialNumber);
 
     env->DeleteLocalRef(serialNumber);
     env->DeleteLocalRef(productName);
@@ -199,7 +200,7 @@
         return -1;
     }
     method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
-            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
+            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
     if (method_beginUsbDeviceAdded == NULL) {
         ALOGE("Can't find beginUsbDeviceAdded");
         return -1;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 31d7f74..c886c4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -182,6 +182,7 @@
     private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
     private static final String ATTR_SETUP_COMPLETE = "setup-complete";
     private static final String ATTR_PREFERRED_SETUP_ACTIVITY = "setup-activity";
+    private static final String ATTR_PERMISSION_POLICY = "permission-policy";
 
     private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
 
@@ -191,6 +192,9 @@
             StatusBarManager.DISABLE_NOTIFICATION_ALERTS |
             StatusBarManager.DISABLE_SEARCH;
 
+    private static final int STATUS_BAR_DISABLE2_MASK =
+            StatusBarManager.DISABLE2_QUICK_SETTINGS;
+
     private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS;
     static {
         DEVICE_OWNER_USER_RESTRICTIONS = new HashSet();
@@ -300,6 +304,7 @@
         int mPasswordOwner = -1;
         long mLastMaximumTimeToLock = -1;
         boolean mUserSetupComplete = false;
+        int mPermissionPolicy;
 
         final HashMap<ComponentName, ActiveAdmin> mAdminMap = new HashMap<>();
         final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
@@ -1409,6 +1414,10 @@
                 out.attribute(null, ATTR_SETUP_COMPLETE,
                         Boolean.toString(true));
             }
+            if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) {
+                out.attribute(null, ATTR_PERMISSION_POLICY,
+                        Integer.toString(policy.mPermissionPolicy));
+            }
             if (policy.mDelegatedCertInstallerPackage != null) {
                 out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
                         policy.mDelegatedCertInstallerPackage);
@@ -1537,6 +1546,10 @@
             if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
                 policy.mUserSetupComplete = true;
             }
+            String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY);
+            if (!TextUtils.isEmpty(permissionPolicy)) {
+                policy.mPermissionPolicy = Integer.parseInt(permissionPolicy);
+            }
             policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
                     ATTR_DELEGATED_CERT_INSTALLER);
             String preferredSetupActivity =
@@ -4052,11 +4065,12 @@
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         synchronized (this) {
-            if (mDeviceOwner != null) {
-                return mDeviceOwner.getDeviceOwnerName();
+            if (mDeviceOwner == null || !mDeviceOwner.hasDeviceOwner()) {
+                return null;
             }
+            String deviceOwnerPackage = mDeviceOwner.getDeviceOwnerPackageName();
+            return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_OWNER);
         }
-        return null;
     }
 
     // Returns the active device owner or null if there is no device owner.
@@ -4253,14 +4267,22 @@
             return;
         }
         UserHandle callingUser = Binder.getCallingUserHandle();
+        int userId = callingUser.getIdentifier();
         // Check if this is the profile owner who is calling
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         synchronized (this) {
+            // Reset some of the profile-owner policies
+            DevicePolicyData policy = getUserData(userId);
+            policy.mPermissionPolicy = DevicePolicyManager.PERMISSION_POLICY_PROMPT;
+            policy.mDelegatedCertInstallerPackage = null;
+            policy.mStatusBarEnabledState = true;
+            saveSettingsLocked(userId);
+
             long ident = Binder.clearCallingIdentity();
             try {
                 clearUserRestrictions(callingUser);
                 if (mDeviceOwner != null) {
-                    mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
+                    mDeviceOwner.removeProfileOwner(userId);
                     mDeviceOwner.writeOwnerFile();
                 }
             } finally {
@@ -4405,7 +4427,6 @@
         if (profileOwner == null) {
             return null;
         }
-
         DevicePolicyData policy = getUserData(userHandle);
         final int n = policy.mAdminList.size();
         for (int i = 0; i < n; i++) {
@@ -4423,13 +4444,37 @@
             return null;
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-
-        synchronized (this) {
-            if (mDeviceOwner != null) {
-                return mDeviceOwner.getProfileOwnerName(userHandle);
-            }
+        ComponentName profileOwner = getProfileOwner(userHandle);
+        if (profileOwner == null) {
+            return null;
         }
-        return null;
+        return getApplicationLabel(profileOwner.getPackageName(), userHandle);
+    }
+
+    /**
+     * Canonical name for a given package.
+     */
+    private String getApplicationLabel(String packageName, int userHandle) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            final Context userContext;
+            try {
+                UserHandle handle = new UserHandle(userHandle);
+                userContext = mContext.createPackageContextAsUser(packageName, 0, handle);
+            } catch (PackageManager.NameNotFoundException nnfe) {
+                Log.w(LOG_TAG, packageName + " is not installed for user " + userHandle, nnfe);
+                return null;
+            }
+            ApplicationInfo appInfo = userContext.getApplicationInfo();
+            CharSequence result = null;
+            if (appInfo != null) {
+                PackageManager pm = userContext.getPackageManager();
+                result = pm.getApplicationLabel(appInfo);
+            }
+            return result != null ? result.toString() : null;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
@@ -6022,8 +6067,10 @@
             IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
                     ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
             if (statusBarService != null) {
-                int flags = enabled ? StatusBarManager.DISABLE_NONE : STATUS_BAR_DISABLE_MASK;
-                statusBarService.disableForUser(flags, mToken, mContext.getPackageName(), userId);
+                int flags1 = enabled ? StatusBarManager.DISABLE_NONE : STATUS_BAR_DISABLE_MASK;
+                int flags2 = enabled ? StatusBarManager.DISABLE2_NONE : STATUS_BAR_DISABLE2_MASK;
+                statusBarService.disableForUser(flags1, mToken, mContext.getPackageName(), userId);
+                statusBarService.disable2ForUser(flags2, mToken, mContext.getPackageName(), userId);
             }
         } catch (RemoteException e) {
             Slog.e(LOG_TAG, "Failed to disable the status bar", e);
@@ -6261,4 +6308,48 @@
             }
         }
     }
+
+    @Override
+    public void setPermissionPolicy(ComponentName admin, int policy) throws RemoteException {
+        int userId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            DevicePolicyData userPolicy = getUserData(userId);
+            if (userPolicy.mPermissionPolicy != policy) {
+                userPolicy.mPermissionPolicy = policy;
+                saveSettingsLocked(userId);
+            }
+        }
+    }
+
+    @Override
+    public int getPermissionPolicy(ComponentName admin) throws RemoteException {
+        int userId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            DevicePolicyData userPolicy = getUserData(userId);
+            return userPolicy.mPermissionPolicy;
+        }
+    }
+
+    @Override
+    public boolean setPermissionGranted(ComponentName admin, String packageName,
+            String permission, boolean granted) throws RemoteException {
+        UserHandle user = Binder.getCallingUserHandle();
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                if (granted) {
+                    mContext.getPackageManager().grantPermission(packageName, permission, user);
+                } else {
+                    mContext.getPackageManager().revokePermission(packageName, permission, user);
+                }
+                return true;
+            } catch (SecurityException se) {
+                return false;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 593853c..2922130 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -76,7 +76,6 @@
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.UserManagerService;
-import com.android.server.power.DeviceIdleController;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.restrictions.RestrictionsManagerService;
@@ -599,6 +598,8 @@
                     mSystemServiceManager.startService(PersistentDataBlockService.class);
                 }
 
+                mSystemServiceManager.startService(DeviceIdleController.class);
+
                 // Always start the Device Policy Manager, so that the API is compatible with
                 // API8.
                 mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
@@ -965,7 +966,6 @@
 
         if (!disableNonCoreServices) {
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
-            mSystemServiceManager.startService(DeviceIdleController.class);
         }
 
         // Before things start rolling, be sure we have decided whether
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index a8c739c..0ab1657 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -507,7 +507,8 @@
         }
         mBinding = true;
         mContext.bindServiceAsUser(mIntent, mServiceConnection,
-                Context.BIND_AUTO_CREATE, new UserHandle(mUserId));
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                new UserHandle(mUserId));
     }
 
     private void ensureUnbound() {
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 7ab3840..85c876a 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -365,7 +365,7 @@
         }
 
         mContext.bindServiceAsUser(mIntent, mServiceConnection,
-                Context.BIND_AUTO_CREATE, mUserHandle);
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, mUserHandle);
 
         final long startMillis = SystemClock.uptimeMillis();
         while (true) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index fbdb20b..2557974 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -24,7 +24,6 @@
 import android.util.LongSparseArray;
 import com.android.internal.util.ArrayUtils;
 
-import java.lang.reflect.Field;
 import java.io.File;
 import java.io.IOException;
 import java.security.cert.CertificateException;
@@ -43,53 +42,6 @@
                 "", 1, 0, 0);
     }
 
-    public PublicKey getPubKey(long pkId) throws NoSuchFieldException, IllegalAccessException {
-        Field pkField = mKsms.getClass().getDeclaredField("mPublicKeys");
-        pkField.setAccessible(true);
-        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
-            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(mKsms);
-        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
-        if (pkh == null) {
-            return null;
-        } else {
-            return pkh.getKey();
-        }
-    }
-
-    public int getPubKeyRefCount(long pkId) throws NoSuchFieldException, IllegalAccessException {
-        Field pkField = mKsms.getClass().getDeclaredField("mPublicKeys");
-        pkField.setAccessible(true);
-        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
-            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(mKsms);
-        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
-        if (pkh == null) {
-            return 0;
-        } else {
-            return pkh.getRefCountLPr();
-        }
-    }
-
-    public int getKeySetRefCount(long keysetId) throws NoSuchFieldException, IllegalAccessException {
-        Field ksField = mKsms.getClass().getDeclaredField("mKeySets");
-        ksField.setAccessible(true);
-        LongSparseArray<KeySetHandle> mKeySets =
-            (LongSparseArray<KeySetHandle>) ksField.get(mKsms);
-        KeySetHandle ksh = mKeySets.get(keysetId);
-        if (ksh == null) {
-            return 0;
-        } else {
-            return ksh.getRefCountLPr();
-        }
-    }
-
-    public LongSparseArray<ArraySet<Long>> getKeySetMapping()
-            throws NoSuchFieldException, IllegalAccessException {
-        Field ksField = mKsms.getClass().getDeclaredField("mKeySetMapping");
-        ksField.setAccessible(true);
-        return (LongSparseArray<ArraySet<Long>>) ksField.get(mKsms);
-    }
-
-
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -168,10 +120,10 @@
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -198,10 +150,10 @@
         /* add again, to represent upgrade of package */
         mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -231,12 +183,12 @@
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(0, getPubKeyRefCount(1));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyB, getPubKey(2));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(2);
         assertEquals(1, mapping.size());
@@ -269,13 +221,13 @@
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyA, getPubKey(1));
-        assertEquals(keyB, getPubKey(2));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(2, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -312,10 +264,10 @@
         mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys2);
 
         /* verify first is unchanged */
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(2, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -323,9 +275,9 @@
         assertEquals(1, ps1.keySetData.getProperSigningKeySet());
 
         /* verify second */
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyB, getPubKey(2));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
         mapping = ksMapping.get(2);
         assertEquals(1, mapping.size());
         assertTrue(mapping.contains(new  Long(2)));
@@ -353,10 +305,10 @@
         /* add again for second package */
         mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
 
-        assertEquals(2, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -388,13 +340,13 @@
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(2, getPubKeyRefCount(1));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyA, getPubKey(1));
-        assertEquals(keyB, getPubKey(2));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(2, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(2, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -429,16 +381,17 @@
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(0, getPubKeyRefCount(1));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(1, getPubKeyRefCount(3));
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
 
         /* the pub key is removed w/prev keyset and may be either 2 or 3 */
-        assertTrue(keyA.equals(getPubKey(2)) && keyB.equals(getPubKey(3))
-                   || keyA.equals(getPubKey(3)) && keyB.equals(getPubKey(2)));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertTrue(keyA.equals(KeySetUtils.getPubKey(mKsms, 2)) || keyA.equals(KeySetUtils.getPubKey(mKsms, 3)));
+        assertTrue(keyB.equals(KeySetUtils.getPubKey(mKsms, 2)) || keyB.equals(KeySetUtils.getPubKey(mKsms, 3)));
+        assertFalse(KeySetUtils.getPubKey(mKsms, 2).equals(KeySetUtils.getPubKey(mKsms, 3)));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(2);
         assertEquals(2, mapping.size());
@@ -462,10 +415,10 @@
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -490,10 +443,10 @@
         definedKS.put("aliasA2", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(2, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        assertEquals(keyA, getPubKey(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(1);
         assertEquals(1, mapping.size());
@@ -527,12 +480,12 @@
         definedKS.put("aliasB", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(0, getPubKeyRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyB, getPubKey(2));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(2);
         assertEquals(1, mapping.size());
@@ -566,12 +519,12 @@
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(0, getPubKeyRefCount(1));
-        assertEquals(1, getKeySetRefCount(2));
-        assertEquals(1, getPubKeyRefCount(2));
-        assertEquals(keyB, getPubKey(2));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(2);
         assertEquals(1, mapping.size());
@@ -608,10 +561,10 @@
         definedKS.put("aliasC", keys1);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(1, getKeySetRefCount(3));
-        assertEquals(1, getPubKeyRefCount(3));
-        assertEquals(keyC, getPubKey(3));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
+        assertEquals(keyC, KeySetUtils.getPubKey(mKsms, 3));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(2, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(3);
         assertEquals(1, mapping.size());
@@ -619,13 +572,13 @@
         assertEquals(new Long(3), ps.keySetData.getAliases().get("aliasC"));
 
         /* either keyset w/keyA or w/keyB was added first, address both cases */
-        if (1 == getKeySetRefCount(1)) {
+        if (1 == KeySetUtils.getKeySetRefCount(mKsms, 1)) {
 
             /* keyB was added first and should have keyset 1 and pub-key 1 */
-            assertEquals(1, getPubKeyRefCount(1));
-            assertEquals(0, getKeySetRefCount(2));
-            assertEquals(0, getPubKeyRefCount(2));
-            assertEquals(keyB, getPubKey(1));
+            assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+            assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2));
+            assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+            assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 1));
             mapping = ksMapping.get(1);
             assertEquals(1, mapping.size());
             assertTrue(mapping.contains(new Long(1)));
@@ -633,11 +586,11 @@
         } else {
 
             /* keyA was added first and keyB has id 2 */
-            assertEquals(1, getKeySetRefCount(2));
-            assertEquals(1, getPubKeyRefCount(2));
-            assertEquals(0, getKeySetRefCount(1));
-            assertEquals(0, getPubKeyRefCount(1));
-            assertEquals(keyB, getPubKey(2));
+            assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
+            assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+            assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+            assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+            assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
             mapping = ksMapping.get(2);
             assertEquals(1, mapping.size());
             assertTrue(mapping.contains(new Long(2)));
@@ -674,14 +627,14 @@
         definedKS.put("aliasA", keys1);
         mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(0, getKeySetRefCount(2));
-        assertEquals(1, getKeySetRefCount(3));
-        assertEquals(0, getPubKeyRefCount(1));
-        assertEquals(0, getPubKeyRefCount(2));
-        assertEquals(1, getPubKeyRefCount(3));
-        assertEquals(keyA, getPubKey(3));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
+        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 3));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         ArraySet<Long> mapping = ksMapping.get(3);
         assertEquals(1, mapping.size());
@@ -780,9 +733,9 @@
 
         /* remove its references */
         mKsms.removeAppKeySetDataLPw(ps.name);
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(0, getPubKeyRefCount(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(0, ksMapping.size());
         assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps.keySetData.getProperSigningKeySet());
     }
@@ -807,9 +760,9 @@
         /* remove references from first package */
         mKsms.removeAppKeySetDataLPw(ps1.name);
 
-        assertEquals(1, getKeySetRefCount(1));
-        assertEquals(1, getPubKeyRefCount(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(1, ksMapping.size());
         assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps1.keySetData.getProperSigningKeySet());
         assertEquals(1, ps2.keySetData.getProperSigningKeySet());
@@ -840,9 +793,9 @@
         mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS);
         mKsms.removeAppKeySetDataLPw(ps.name);
 
-        assertEquals(0, getKeySetRefCount(1));
-        assertEquals(0, getPubKeyRefCount(1));
-        LongSparseArray<ArraySet<Long>> ksMapping = getKeySetMapping();
+        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
+        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
         assertEquals(0, ksMapping.size());
         assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps.keySetData.getProperSigningKeySet());
         assertEquals(0, ps.keySetData.getAliases().size());
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java b/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java
new file mode 100644
index 0000000..9e1a366
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.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.pm;
+
+import android.util.ArraySet;
+import android.util.LongSparseArray;
+
+import java.lang.reflect.Field;
+import java.security.PublicKey;
+
+public class KeySetUtils {
+
+    public static PublicKey getPubKey(KeySetManagerService ksms, long pkId)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field pkField = ksms.getClass().getDeclaredField("mPublicKeys");
+        pkField.setAccessible(true);
+        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
+            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(ksms);
+        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
+        if (pkh == null) {
+            return null;
+        } else {
+            return pkh.getKey();
+        }
+    }
+
+    public static int getPubKeyRefCount(KeySetManagerService ksms, long pkId)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field pkField = ksms.getClass().getDeclaredField("mPublicKeys");
+        pkField.setAccessible(true);
+        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
+            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(ksms);
+        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
+        if (pkh == null) {
+            return 0;
+        } else {
+            return pkh.getRefCountLPr();
+        }
+    }
+
+    public static int getKeySetRefCount(KeySetManagerService ksms, long keysetId)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field ksField = ksms.getClass().getDeclaredField("mKeySets");
+        ksField.setAccessible(true);
+        LongSparseArray<KeySetHandle> mKeySets =
+            (LongSparseArray<KeySetHandle>) ksField.get(ksms);
+        KeySetHandle ksh = mKeySets.get(keysetId);
+        if (ksh == null) {
+            return 0;
+        } else {
+            return ksh.getRefCountLPr();
+        }
+    }
+
+    public static LongSparseArray<ArraySet<Long>> getKeySetMapping(KeySetManagerService ksms)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field ksField = ksms.getClass().getDeclaredField("mKeySetMapping");
+        ksField.setAccessible(true);
+        return (LongSparseArray<ArraySet<Long>>) ksField.get(ksms);
+    }
+
+    public static Long getLastIssuedKeyId(KeySetManagerService ksms)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field ksField = ksms.getClass().getDeclaredField("lastIssuedKeyId");
+        ksField.setAccessible(true);
+        return (Long) ksField.get(ksms);
+    }
+
+    public static Long getLastIssuedKeySetId(KeySetManagerService ksms)
+            throws NoSuchFieldException, IllegalAccessException {
+        Field ksField = ksms.getClass().getDeclaredField("lastIssuedKeySetId");
+        ksField.setAccessible(true);
+        return (Long) ksField.get(ksms);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index a3f3a5d..ed1db6f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -21,15 +21,21 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import android.content.Context;
+import android.content.pm.PackageParser;
 import android.test.AndroidTestCase;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.LongSparseArray;
 
 import com.android.internal.os.AtomicFile;
 
+import java.lang.reflect.Constructor;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.security.PublicKey;
 
 public class PackageManagerSettingsTests extends AndroidTestCase {
     private static final String PACKAGE_NAME_2 = "com.google.app2";
@@ -67,18 +73,24 @@
                 + "</permissions>"
                 + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
                 + "<sigs count=\"1\">"
-                + "<cert index=\"0\" key=\"308886\" />"
+                + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />"
                 + "</sigs>"
+                + "<proper-signing-keyset identifier=\"1\" />"
                 + "</package>"
                 + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
                 + "<sigs count=\"1\">"
                 + "<cert index=\"0\" />"
                 + "</sigs>"
+                + "<proper-signing-keyset identifier=\"1\" />"
+                + "<defined-keyset alias=\"AB\" identifier=\"4\" />"
                 + "</package>"
                 + "<package name=\"com.android.app3\" codePath=\"/system/app/app3.apk\" nativeLibraryPath=\"/data/data/com.android.app3/lib\" flags=\"1\" ft=\"1360e577b60\" it=\"135f2f80d08\" ut=\"1360e577b60\" version=\"15\" userId=\"11030\">"
                 + "<sigs count=\"1\">"
-                + "<cert index=\"1\" key=\"308366\" />"
+                + "<cert index=\"1\" key=\"" + KeySetStrings.ctsKeySetCertB + "\" />"
                 + "</sigs>"
+                + "<proper-signing-keyset identifier=\"2\" />"
+                + "<upgrade-keyset identifier=\"3\" />"
+                + "<defined-keyset alias=\"C\" identifier=\"3\" />"
                 + "</package>"
                 + "<shared-user name=\"com.android.shared1\" userId=\"11000\">"
                 + "<sigs count=\"1\">"
@@ -88,6 +100,30 @@
                 + "<item name=\"android.permission.REBOOT\" />"
                 + "</perms>"
                 + "</shared-user>"
+                + "<keyset-settings version=\"1\">"
+                + "<keys>"
+                + "<public-key identifier=\"1\" value=\"" + KeySetStrings.ctsKeySetPublicKeyA + "\" />"
+                + "<public-key identifier=\"2\" value=\"" + KeySetStrings.ctsKeySetPublicKeyB + "\" />"
+                + "<public-key identifier=\"3\" value=\"" + KeySetStrings.ctsKeySetPublicKeyC + "\" />"
+                + "</keys>"
+                + "<keysets>"
+                + "<keyset identifier=\"1\">"
+                + "<key-id identifier=\"1\" />"
+                + "</keyset>"
+                + "<keyset identifier=\"2\">"
+                + "<key-id identifier=\"2\" />"
+                + "</keyset>"
+                + "<keyset identifier=\"3\">"
+                + "<key-id identifier=\"3\" />"
+                + "</keyset>"
+                + "<keyset identifier=\"4\">"
+                + "<key-id identifier=\"1\" />"
+                + "<key-id identifier=\"2\" />"
+                + "</keyset>"
+                + "</keysets>"
+                + "<lastIssuedKeyId value=\"3\" />"
+                + "<lastIssuedKeySetId value=\"4\" />"
+                + "</keyset-settings>"
                 + "</packages>").getBytes());
     }
 
@@ -131,6 +167,104 @@
         writePackagesList();
     }
 
+    private void createUserManagerServiceRef() throws ReflectiveOperationException {
+        Constructor<UserManagerService> umsc =
+                UserManagerService.class.getDeclaredConstructor(
+                        Context.class,
+                        PackageManagerService.class,
+                        Object.class,
+                        Object.class,
+                        File.class,
+                        File.class);
+        umsc.setAccessible(true);
+        UserManagerService ums = umsc.newInstance(getContext(), null,
+                new Object(), new Object(), getContext().getFilesDir(),
+                new File(getContext().getFilesDir(), "user"));
+    }
+
+    private void verifyKeySetMetaData(Settings settings)
+            throws ReflectiveOperationException, IllegalAccessException {
+        ArrayMap<String, PackageSetting> packages = settings.mPackages;
+        KeySetManagerService ksms = settings.mKeySetManagerService;
+
+        /* verify keyset and public key ref counts */
+        assertEquals(2, KeySetUtils.getKeySetRefCount(ksms, 1));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 2));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 3));
+        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 4));
+        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 1));
+        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 2));
+        assertEquals(1, KeySetUtils.getPubKeyRefCount(ksms, 3));
+
+        /* verify public keys properly read */
+        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+        assertEquals(keyA, KeySetUtils.getPubKey(ksms, 1));
+        assertEquals(keyB, KeySetUtils.getPubKey(ksms, 2));
+        assertEquals(keyC, KeySetUtils.getPubKey(ksms, 3));
+
+        /* verify mapping is correct (ks -> pub keys) */
+        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(ksms);
+        ArraySet<Long> mapping = ksMapping.get(1);
+        assertEquals(1, mapping.size());
+        assertTrue(mapping.contains(new Long(1)));
+        mapping = ksMapping.get(2);
+        assertEquals(1, mapping.size());
+        assertTrue(mapping.contains(new Long(2)));
+        mapping = ksMapping.get(3);
+        assertEquals(1, mapping.size());
+        assertTrue(mapping.contains(new Long(3)));
+        mapping = ksMapping.get(4);
+        assertEquals(2, mapping.size());
+        assertTrue(mapping.contains(new Long(1)));
+        assertTrue(mapping.contains(new Long(2)));
+
+        /* verify lastIssuedIds are consistent */
+        assertEquals(new Long(3), KeySetUtils.getLastIssuedKeyId(ksms));
+        assertEquals(new Long(4), KeySetUtils.getLastIssuedKeySetId(ksms));
+
+        /* verify packages have been given the appropriat information */
+        PackageSetting ps = packages.get("com.google.app1");
+        assertEquals(1, ps.keySetData.getProperSigningKeySet());
+        ps = packages.get("com.google.app2");
+        assertEquals(1, ps.keySetData.getProperSigningKeySet());
+        assertEquals(new Long(4), ps.keySetData.getAliases().get("AB"));
+        ps = packages.get("com.android.app3");
+        assertEquals(2, ps.keySetData.getProperSigningKeySet());
+        assertEquals(new Long(3), ps.keySetData.getAliases().get("C"));
+        assertEquals(1, ps.keySetData.getUpgradeKeySets().length);
+        assertEquals(3, ps.keySetData.getUpgradeKeySets()[0]);
+    }
+
+    /* make sure our initialized keysetmanagerservice metadata matches packages.xml */
+    public void testReadKeySetSettings()
+            throws ReflectiveOperationException, IllegalAccessException {
+
+        /* write out files and read */
+        writeOldFiles();
+        createUserManagerServiceRef();
+        Settings settings = new Settings(getContext().getFilesDir(), new Object());
+        assertEquals(true, settings.readLPw(null, null, 0, false));
+        verifyKeySetMetaData(settings);
+    }
+
+    /* read in data, write it out, and read it back in.  Verify same. */
+    public void testWriteKeySetSettings()
+            throws ReflectiveOperationException, IllegalAccessException {
+
+        /* write out files and read */
+        writeOldFiles();
+        createUserManagerServiceRef();
+        Settings settings = new Settings(getContext().getFilesDir(), new Object());
+        assertEquals(true, settings.readLPw(null, null, 0, false));
+
+        /* write out, read back in and verify the same */
+        settings.writeLPr();
+        assertEquals(true, settings.readLPw(null, null, 0, false));
+        verifyKeySetMetaData(settings);
+    }
+
     public void testSettingsReadOld() {
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
@@ -149,9 +283,11 @@
         assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
     }
 
-    public void testNewPackageRestrictionsFile() {
+    public void testNewPackageRestrictionsFile() throws ReflectiveOperationException {
+
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
+        createUserManagerServiceRef();
         Settings settings = new Settings(getContext().getFilesDir(), new Object());
         assertEquals(true, settings.readLPw(null, null, 0, false));
         settings.writeLPr();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 04984d3..c2e61c6 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -28,7 +28,6 @@
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
-import android.appwidget.AppWidgetManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -41,6 +40,7 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -81,6 +81,8 @@
     private static final long TWENTY_MINUTES = 20 * 60 * 1000;
     private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
+    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 2L * 24 * 60 * 60 * 1000; // 1 day
+    static final long DEFAULT_CHECK_IDLE_INTERVAL = 8 * 3600 * 1000; // 8 hours
 
     // Handler message types.
     static final int MSG_REPORT_EVENT = 0;
@@ -88,6 +90,7 @@
     static final int MSG_REMOVE_USER = 2;
     static final int MSG_INFORM_LISTENERS = 3;
     static final int MSG_RESET_LAST_TIMESTAMP = 4;
+    static final int MSG_CHECK_IDLE_STATES = 5;
 
     private final Object mLock = new Object();
     Handler mHandler;
@@ -98,9 +101,11 @@
     private File mUsageStatsDir;
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
+    boolean mAppIdleParoled;
 
-    private static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 1L * 24 * 60 * 60 * 1000; // 1 day
-    private long mAppIdleDurationMillis;
+    long mAppIdleDurationMillis;
+
+    long mCheckIdleIntervalMillis = DEFAULT_CHECK_IDLE_INTERVAL;
 
     private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
             mPackageAccessListeners = new ArrayList<>();
@@ -113,6 +118,7 @@
     public void onStart() {
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+
         mHandler = new H(BackgroundThread.get().getLooper());
 
         File systemDataDir = new File(Environment.getDataDirectory(), "system");
@@ -123,9 +129,14 @@
                     + mUsageStatsDir.getAbsolutePath());
         }
 
-        getContext().registerReceiver(new UserRemovedReceiver(),
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
+        IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        userActions.addAction(Intent.ACTION_USER_STARTED);
+        getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
+                null, null);
 
+        IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
+        deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
+        getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
         synchronized (mLock) {
             cleanUpRemovedUsersLocked();
         }
@@ -147,18 +158,35 @@
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             // Observe changes to the threshold
             new SettingsObserver(mHandler).registerObserver();
+        } else if (phase == PHASE_BOOT_COMPLETED) {
+            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
         }
     }
 
-    private class UserRemovedReceiver extends BroadcastReceiver {
+    private class UserActionsReceiver extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
-                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 if (userId >= 0) {
                     mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
                 }
+            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+                if (userId >=0) {
+                    postCheckIdleStates();
+                }
+            }
+        }
+    }
+
+    private class DeviceStateReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (BatteryManager.ACTION_CHARGING.equals(action)
+                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
+                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
             }
         }
     }
@@ -195,6 +223,49 @@
         }
     }
 
+    void setAppIdleParoled(boolean paroled) {
+        synchronized (mLock) {
+            if (mAppIdleParoled != paroled) {
+                mAppIdleParoled = paroled;
+                postCheckIdleStates();
+            }
+        }
+    }
+
+    void postCheckIdleStates() {
+        mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
+        mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
+    }
+
+    /** Check all running users' apps to see if they enter an idle state. */
+    void checkIdleStates() {
+        final int[] runningUsers;
+        try {
+            runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+        } catch (RemoteException re) {
+            return;
+        }
+
+        for (int i = 0; i < runningUsers.length; i++) {
+            final int userId = runningUsers[i];
+            List<PackageInfo> packages =
+                    getContext().getPackageManager().getInstalledPackages(
+                            PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_UNINSTALLED_PACKAGES,
+                            userId);
+            synchronized (mLock) {
+                final int packageCount = packages.size();
+                for (int p = 0; p < packageCount; p++) {
+                    final String packageName = packages.get(p).packageName;
+                    final boolean isIdle = isAppIdle(packageName, userId);
+                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
+                            userId, isIdle ? 1 : 0, packageName));
+                }
+            }
+        }
+        mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
+    }
+
     private static void deleteRecursively(File f) {
         File[] files = f.listFiles();
         if (files != null) {
@@ -291,7 +362,7 @@
     void resetLastTimestamp(String packageName, int userId, boolean idle) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0);
+            final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0) - 5000;
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
@@ -409,14 +480,22 @@
 
     private boolean hasPassedIdleDuration(long lastUsed) {
         final long now = System.currentTimeMillis();
-        return lastUsed < now - mAppIdleDurationMillis;
+        return lastUsed <= now - mAppIdleDurationMillis;
     }
 
     boolean isAppIdle(String packageName, int userId) {
         if (packageName == null) return false;
+        synchronized (mLock) {
+            // Temporary exemption, probably due to device charging or occasional allowance to
+            // be allowed to sync, etc.
+            if (mAppIdleParoled) {
+                return false;
+            }
+        }
         if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) {
             return false;
         }
+        // TODO: Optimize this check
         if (isActiveDeviceAdmin(packageName, userId)) {
             return false;
         }
@@ -518,6 +597,9 @@
                     resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1);
                     break;
 
+                case MSG_CHECK_IDLE_STATES:
+                    checkIdleStates();
+                    break;
                 default:
                     super.handleMessage(msg);
                     break;
@@ -544,7 +626,9 @@
             mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
                     Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
                     UserHandle.USER_OWNER);
-            // TODO: Check if we need to update idle states of all the apps
+            mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
+                    mAppIdleDurationMillis / 4);
+            postCheckIdleStates();
         }
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index daccf95..27c97d0 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -401,6 +401,7 @@
                     Bundle properties = new Bundle();
                     String manufacturer = usbDevice.getManufacturerName();
                     String product = usbDevice.getProductName();
+                    String version = usbDevice.getVersion();
                     String name;
                     if (manufacturer == null || manufacturer.isEmpty()) {
                         name = product;
@@ -412,6 +413,7 @@
                     properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
                     properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
                     properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+                    properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
                     properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
                             usbDevice.getSerialNumber());
                     properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 5b58051..f5f2b07 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -112,7 +112,7 @@
      */
     private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
             int deviceClass, int deviceSubclass, int deviceProtocol,
-            String manufacturerName, String productName, String serialNumber) {
+            String manufacturerName, String productName, int version, String serialNumber) {
 
         if (DEBUG) {
             Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
@@ -149,9 +149,12 @@
                 return false;
             }
 
+            // Create version string in "%.%" format
+            String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
+
             mNewDevice = new UsbDevice(deviceName, vendorID, productID,
                     deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, serialNumber);
+                    manufacturerName, productName, versionString, serialNumber);
 
             mNewConfigurations = new ArrayList<UsbConfiguration>();
             mNewInterfaces = new ArrayList<UsbInterface>();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 61ec162..f439915 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -229,7 +229,7 @@
         Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         intent.setComponent(mComponent);
         mBound = mContext.bindServiceAsUser(intent, mConnection,
-                Context.BIND_AUTO_CREATE, new UserHandle(mUser));
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUser));
         if (!mBound) {
             Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 9634ab8..42eb6c3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -180,7 +180,8 @@
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
-                        Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
+                        Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY
+                                | Context.BIND_FOREGROUND_SERVICE,
                         new UserHandle(mUser));
             }
             mShown = true;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index d92c0c7..9273939 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -19,10 +19,12 @@
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 
 import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -608,7 +610,7 @@
     private final List<String> mChildrenIds = new ArrayList<>();
     private final List<Call> mChildren = new ArrayList<>();
     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
-    private final List<Callback> mCallbacks = new CopyOnWriteArrayList<>();
+    private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
     private final List<Call> mConferenceableCalls = new ArrayList<>();
     private final List<Call> mUnmodifiableConferenceableCalls =
             Collections.unmodifiableList(mConferenceableCalls);
@@ -850,7 +852,20 @@
      * @param callback A {@code Callback}.
      */
     public void registerCallback(Callback callback) {
-        mCallbacks.add(callback);
+        registerCallback(callback, new Handler());
+    }
+
+    /**
+     * Registers a callback to this {@code Call}.
+     *
+     * @param callback A {@code Callback}.
+     * @param handler A handler which command and status changes will be delivered to.
+     */
+    public void registerCallback(Callback callback, Handler handler) {
+        unregisterCallback(callback);
+        if (callback != null && handler != null) {
+            mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
+        }
     }
 
     /**
@@ -860,7 +875,12 @@
      */
     public void unregisterCallback(Callback callback) {
         if (callback != null) {
-            mCallbacks.remove(callback);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                if (record.getCallback() == callback) {
+                    mCallbackRecords.remove(record);
+                    break;
+                }
+            }
         }
     }
 
@@ -1021,57 +1041,120 @@
         }
     }
 
-    private void fireStateChanged(int newState) {
-        for (Callback callback : mCallbacks) {
-            callback.onStateChanged(this, newState);
+    private void fireStateChanged(final int newState) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onStateChanged(call, newState);
+                }
+            });
         }
     }
 
-    private void fireParentChanged(Call newParent) {
-        for (Callback callback : mCallbacks) {
-            callback.onParentChanged(this, newParent);
+    private void fireParentChanged(final Call newParent) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onParentChanged(call, newParent);
+                }
+            });
         }
     }
 
-    private void fireChildrenChanged(List<Call> children) {
-        for (Callback callback : mCallbacks) {
-            callback.onChildrenChanged(this, children);
+    private void fireChildrenChanged(final List<Call> children) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onChildrenChanged(call, children);
+                }
+            });
         }
     }
 
-    private void fireDetailsChanged(Details details) {
-        for (Callback callback : mCallbacks) {
-            callback.onDetailsChanged(this, details);
+    private void fireDetailsChanged(final Details details) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onDetailsChanged(call, details);
+                }
+            });
         }
     }
 
-    private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
-        for (Callback callback : mCallbacks) {
-            callback.onCannedTextResponsesLoaded(this, cannedTextResponses);
+    private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
+                }
+            });
         }
     }
 
-    private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
-        for (Callback callback : mCallbacks) {
-            callback.onVideoCallChanged(this, videoCall);
+    private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onVideoCallChanged(call, videoCall);
+                }
+            });
         }
     }
 
-    private void firePostDialWait(String remainingPostDialSequence) {
-        for (Callback callback : mCallbacks) {
-            callback.onPostDialWait(this, remainingPostDialSequence);
+    private void firePostDialWait(final String remainingPostDialSequence) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onPostDialWait(call, remainingPostDialSequence);
+                }
+            });
         }
     }
 
     private void fireCallDestroyed() {
-        for (Callback callback : mCallbacks) {
-            callback.onCallDestroyed(this);
+        for (CallbackRecord<Callback> record: mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onCallDestroyed(call);
+                }
+            });
         }
     }
 
     private void fireConferenceableCallsChanged() {
-        for (Callback callback : mCallbacks) {
-            callback.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
+                }
+            });
         }
     }
 }
diff --git a/telecomm/java/android/telecom/CallbackRecord.java b/telecomm/java/android/telecom/CallbackRecord.java
new file mode 100644
index 0000000..1a81925
--- /dev/null
+++ b/telecomm/java/android/telecom/CallbackRecord.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telecom;
+
+import android.os.Handler;
+
+
+/**
+ * This class is used to associate a generic callback of type T with a handler to which commands and
+ * status updates will be delivered to.
+ *
+ * @hide
+ */
+class CallbackRecord<T> {
+    private final T mCallback;
+    private final Handler mHandler;
+
+    public CallbackRecord(T callback, Handler handler) {
+        mCallback = callback;
+        mHandler = handler;
+    }
+
+    public T getCallback() {
+        return mCallback;
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+}
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 93823d1..b5d566a 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -14,7 +14,6 @@
 
 package android.telecom;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -52,13 +51,12 @@
         }
 
         // Only make the change if the new package belongs to a valid phone application
-        List<ComponentName> componentNames = getInstalledDialerApplications(context);
-        final ComponentName foundComponent = getComponentName(componentNames, packageName);
+        List<String> packageNames = getInstalledDialerApplications(context);
 
-        if (foundComponent != null) {
+        if (packageNames.contains(packageName)) {
             // Update the secure setting.
             Settings.Secure.putString(context.getContentResolver(),
-                    Settings.Secure.DIALER_DEFAULT_APPLICATION, foundComponent.getPackageName());
+                    Settings.Secure.DIALER_DEFAULT_APPLICATION, packageName);
         }
     }
 
@@ -73,29 +71,31 @@
      *
      * @hide
      * */
-    public static ComponentName getDefaultDialerApplication(Context context) {
+    public static String getDefaultDialerApplication(Context context) {
         String defaultPackageName = Settings.Secure.getString(context.getContentResolver(),
                 Settings.Secure.DIALER_DEFAULT_APPLICATION);
 
-        final List<ComponentName> componentNames = getInstalledDialerApplications(context);
-        if (!TextUtils.isEmpty(defaultPackageName)) {
-            final ComponentName defaultDialer =
-                    getComponentName(componentNames, defaultPackageName);
-            if (defaultDialer != null) {
-                return defaultDialer;
-            }
+
+        final List<String> packageNames = getInstalledDialerApplications(context);
+
+        // Verify that the default dialer has not been disabled or uninstalled.
+        if (packageNames.contains(defaultPackageName)) {
+            return defaultPackageName;
         }
 
         // No user-set dialer found, fallback to system dialer
-        String systemDialer = getTelecomManager(context).getSystemDialerPackage();
+        String systemDialerPackageName = getTelecomManager(context).getSystemDialerPackage();
 
-        if (TextUtils.isEmpty(systemDialer)) {
+        if (TextUtils.isEmpty(systemDialerPackageName)) {
             // No system dialer configured at build time
             return null;
         }
 
-        // Verify that the system dialer has not been disabled.
-        return getComponentName(componentNames, systemDialer);
+        if (packageNames.contains(systemDialerPackageName)) {
+            return systemDialerPackageName;
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -109,44 +109,25 @@
      *
      * @hide
      **/
-    public static List<ComponentName> getInstalledDialerApplications(Context context) {
+    public static List<String> getInstalledDialerApplications(Context context) {
         PackageManager packageManager = context.getPackageManager();
 
         // Get the list of apps registered for the DIAL intent with empty scheme
         Intent intent = new Intent(Intent.ACTION_DIAL);
         List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
 
-        List<ComponentName> componentNames = new ArrayList<ComponentName> ();
+        List<String> packageNames = new ArrayList<>();
 
         for (ResolveInfo resolveInfo : resolveInfoList) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
             if (activityInfo == null) {
                 continue;
             }
-            final ComponentName componentName =
-                    new ComponentName(activityInfo.packageName, activityInfo.name);
-            componentNames.add(componentName);
+            packageNames.add(activityInfo.packageName);
         }
 
         // TODO: Filter for apps that don't handle DIAL intent with tel scheme
-        return componentNames;
-    }
-
-    /**
-     * Returns the {@link ComponentName} for the installed dialer application for a given package
-     * name.
-     *
-     * @param context A valid context.
-     * @param packageName to retrieve the {@link ComponentName} for.
-     *
-     * @return The {@link ComponentName} for the installed dialer application corresponding to the
-     * package name, or null if none is found.
-     *
-     * @hide
-     */
-    public static ComponentName getDialerApplicationForPackageName(Context context,
-            String packageName) {
-        return getComponentName(getInstalledDialerApplications(context), packageName);
+        return packageNames;
     }
 
     /**
@@ -170,25 +151,6 @@
                 || packageName.equals(tm.getSystemDialerPackage());
     }
 
-    /**
-     * Returns the component from a list of application components that corresponds to the package
-     * name.
-     *
-     * @param componentNames A list of component names
-     * @param packageName The package name to look for
-     * @return The {@link ComponentName} that matches the provided packageName, or null if not
-     *         found.
-     */
-    private static ComponentName getComponentName(List<ComponentName> componentNames,
-            String packageName) {
-        for (ComponentName componentName : componentNames) {
-            if (TextUtils.equals(packageName, componentName.getPackageName())) {
-                return componentName;
-            }
-        }
-        return null;
-    }
-
     private static TelecomManager getTelecomManager(Context context) {
         return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
     }
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 2c8415a..3cb4e87 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -362,6 +362,9 @@
      */
     public static abstract class VideoCall {
 
+        /** @hide */
+        public abstract void destroy();
+
         /**
          * Registers a callback to receive commands and state changes for video calls.
          *
@@ -370,9 +373,17 @@
         public abstract void registerCallback(VideoCall.Callback callback);
 
         /**
+         * Registers a callback to receive commands and state changes for video calls.
+         *
+         * @param callback The video call callback.
+         * @param handler A handler which commands and status changes will be delivered to.
+         */
+        public abstract void registerCallback(VideoCall.Callback callback, Handler handler);
+
+        /**
          * Clears the video call listener set via {@link #registerCallback}.
          */
-        public abstract void unregisterCallback();
+        public abstract void unregisterCallback(VideoCall.Callback callback);
 
         /**
          * Sets the camera to be used for video recording in a video call.
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 3d9acda..4cdfd2e 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,7 +125,7 @@
 
         InCallService.VideoCall videoCall = call.getVideoCall();
         if (videoCall != null) {
-            videoCall.unregisterCallback();
+            videoCall.destroy();
         }
         fireCallRemoved(call);
     }
@@ -174,7 +174,7 @@
         for (Call call : mCalls) {
             InCallService.VideoCall videoCall = call.getVideoCall();
             if (videoCall != null) {
-                videoCall.unregisterCallback();
+                videoCall.destroy();
             }
             if (call.getState() != Call.STATE_DISCONNECTED) {
                 call.internalSetDisconnected();
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index fba3ee3..a76bf59 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.telecom.IConnectionService;
 
+import android.os.Handler;
 import android.os.RemoteException;
 
 import java.util.ArrayList;
@@ -49,7 +50,7 @@
     private final String mId;
     private final IConnectionService mConnectionService;
 
-    private final Set<Callback> mCallbacks = new CopyOnWriteArraySet<>();
+    private final Set<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArraySet<>();
     private final List<RemoteConnection> mChildConnections = new CopyOnWriteArrayList<>();
     private final List<RemoteConnection> mUnmodifiableChildConnections =
             Collections.unmodifiableList(mChildConnections);
@@ -77,13 +78,20 @@
         for (RemoteConnection connection : mChildConnections) {
             connection.setConference(null);
         }
-        for (Callback c : mCallbacks) {
-            c.onDestroyed(this);
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final RemoteConference conference = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onDestroyed(conference);
+                }
+            });
         }
     }
 
     /** {@hide} */
-    void setState(int newState) {
+    void setState(final int newState) {
         if (newState != Connection.STATE_ACTIVE &&
                 newState != Connection.STATE_HOLDING &&
                 newState != Connection.STATE_DISCONNECTED) {
@@ -93,42 +101,71 @@
         }
 
         if (mState != newState) {
-            int oldState = mState;
+            final int oldState = mState;
             mState = newState;
-            for (Callback c : mCallbacks) {
-                c.onStateChanged(this, oldState, newState);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onStateChanged(conference, oldState, newState);
+                    }
+                });
             }
         }
     }
 
     /** {@hide} */
-    void addConnection(RemoteConnection connection) {
+    void addConnection(final RemoteConnection connection) {
         if (!mChildConnections.contains(connection)) {
             mChildConnections.add(connection);
             connection.setConference(this);
-            for (Callback c : mCallbacks) {
-                c.onConnectionAdded(this, connection);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onConnectionAdded(conference, connection);
+                    }
+                });
             }
         }
     }
 
     /** {@hide} */
-    void removeConnection(RemoteConnection connection) {
+    void removeConnection(final RemoteConnection connection) {
         if (mChildConnections.contains(connection)) {
             mChildConnections.remove(connection);
             connection.setConference(null);
-            for (Callback c : mCallbacks) {
-                c.onConnectionRemoved(this, connection);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onConnectionRemoved(conference, connection);
+                    }
+                });
             }
         }
     }
 
     /** {@hide} */
-    void setConnectionCapabilities(int connectionCapabilities) {
+    void setConnectionCapabilities(final int connectionCapabilities) {
         if (mConnectionCapabilities != connectionCapabilities) {
             mConnectionCapabilities = connectionCapabilities;
-            for (Callback c : mCallbacks) {
-                c.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onConnectionCapabilitiesChanged(
+                                conference, mConnectionCapabilities);
+                    }
+                });
             }
         }
     }
@@ -137,18 +174,33 @@
     void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
         mConferenceableConnections.clear();
         mConferenceableConnections.addAll(conferenceableConnections);
-        for (Callback c : mCallbacks) {
-            c.onConferenceableConnectionsChanged(this, mUnmodifiableConferenceableConnections);
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final RemoteConference conference = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConferenceableConnectionsChanged(
+                            conference, mUnmodifiableConferenceableConnections);
+                }
+            });
         }
     }
 
     /** {@hide} */
-    void setDisconnected(DisconnectCause disconnectCause) {
+    void setDisconnected(final DisconnectCause disconnectCause) {
         if (mState != Connection.STATE_DISCONNECTED) {
             mDisconnectCause = disconnectCause;
             setState(Connection.STATE_DISCONNECTED);
-            for (Callback c : mCallbacks) {
-                c.onDisconnected(this, disconnectCause);
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onDisconnected(conference, disconnectCause);
+                    }
+                });
             }
         }
     }
@@ -239,10 +291,24 @@
     }
 
     public final void registerCallback(Callback callback) {
-        mCallbacks.add(callback);
+        registerCallback(callback, new Handler());
+    }
+
+    public final void registerCallback(Callback callback, Handler handler) {
+        unregisterCallback(callback);
+        if (callback != null && handler != null) {
+            mCallbackRecords.add(new CallbackRecord(callback, handler));
+        }
     }
 
     public final void unregisterCallback(Callback callback) {
-        mCallbacks.remove(callback);
+        if (callback != null) {
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                if (record.getCallback() == callback) {
+                    mCallbackRecords.remove(record);
+                    break;
+                }
+            }
+        }
     }
 }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 4ecfd50..1493b20 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -21,6 +21,7 @@
 import com.android.internal.telecom.IVideoProvider;
 
 import android.net.Uri;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.Surface;
@@ -392,8 +393,8 @@
      * load factor before resizing, 1 means we only expect a single thread to
      * access the map so make only a single shard
      */
-    private final Set<Callback> mCallbacks = Collections.newSetFromMap(
-            new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
+    private final Set<CallbackRecord> mCallbackRecords = Collections.newSetFromMap(
+            new ConcurrentHashMap<CallbackRecord, Boolean>(8, 0.9f, 1));
     private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>();
     private final List<RemoteConnection> mUnmodifiableconferenceableConnections =
             Collections.unmodifiableList(mConferenceableConnections);
@@ -470,7 +471,20 @@
      * @param callback A {@code Callback}.
      */
     public void registerCallback(Callback callback) {
-        mCallbacks.add(callback);
+        registerCallback(callback, new Handler());
+    }
+
+    /**
+     * Adds a callback to this {@code RemoteConnection}.
+     *
+     * @param callback A {@code Callback}.
+     * @param handler A {@code Handler} which command and status changes will be delivered to.
+     */
+    public void registerCallback(Callback callback, Handler handler) {
+        unregisterCallback(callback);
+        if (callback != null && handler != null) {
+            mCallbackRecords.add(new CallbackRecord(callback, handler));
+        }
     }
 
     /**
@@ -480,7 +494,12 @@
      */
     public void unregisterCallback(Callback callback) {
         if (callback != null) {
-            mCallbacks.remove(callback);
+            for (CallbackRecord record : mCallbackRecords) {
+                if (record.getCallback() == callback) {
+                    mCallbackRecords.remove(record);
+                    break;
+                }
+            }
         }
     }
 
@@ -800,11 +819,18 @@
     /**
      * @hide
      */
-    void setState(int state) {
+    void setState(final int state) {
         if (mState != state) {
             mState = state;
-            for (Callback c: mCallbacks) {
-                c.onStateChanged(this, state);
+            for (CallbackRecord record: mCallbackRecords) {
+                final RemoteConnection connection = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onStateChanged(connection, state);
+                    }
+                });
             }
         }
     }
@@ -812,13 +838,20 @@
     /**
      * @hide
      */
-    void setDisconnected(DisconnectCause disconnectCause) {
+    void setDisconnected(final DisconnectCause disconnectCause) {
         if (mState != Connection.STATE_DISCONNECTED) {
             mState = Connection.STATE_DISCONNECTED;
             mDisconnectCause = disconnectCause;
 
-            for (Callback c : mCallbacks) {
-                c.onDisconnected(this, mDisconnectCause);
+            for (CallbackRecord record : mCallbackRecords) {
+                final RemoteConnection connection = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onDisconnected(connection, disconnectCause);
+                    }
+                });
             }
         }
     }
@@ -826,11 +859,18 @@
     /**
      * @hide
      */
-    void setRingbackRequested(boolean ringback) {
+    void setRingbackRequested(final boolean ringback) {
         if (mRingbackRequested != ringback) {
             mRingbackRequested = ringback;
-            for (Callback c : mCallbacks) {
-                c.onRingbackRequested(this, ringback);
+            for (CallbackRecord record : mCallbackRecords) {
+                final RemoteConnection connection = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onRingbackRequested(connection, ringback);
+                    }
+                });
             }
         }
     }
@@ -838,10 +878,17 @@
     /**
      * @hide
      */
-    void setConnectionCapabilities(int connectionCapabilities) {
+    void setConnectionCapabilities(final int connectionCapabilities) {
         mConnectionCapabilities = connectionCapabilities;
-        for (Callback c : mCallbacks) {
-            c.onConnectionCapabilitiesChanged(this, connectionCapabilities);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConnectionCapabilitiesChanged(connection, connectionCapabilities);
+                }
+            });
         }
     }
 
@@ -849,17 +896,24 @@
      * @hide
      */
     void setDestroyed() {
-        if (!mCallbacks.isEmpty()) {
+        if (!mCallbackRecords.isEmpty()) {
             // Make sure that the callbacks are notified that the call is destroyed first.
             if (mState != Connection.STATE_DISCONNECTED) {
                 setDisconnected(
                         new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed."));
             }
 
-            for (Callback c : mCallbacks) {
-                c.onDestroyed(this);
+            for (CallbackRecord record : mCallbackRecords) {
+                final RemoteConnection connection = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onDestroyed(connection);
+                    }
+                });
             }
-            mCallbacks.clear();
+            mCallbackRecords.clear();
 
             mConnected = false;
         }
@@ -868,90 +922,162 @@
     /**
      * @hide
      */
-    void setPostDialWait(String remainingDigits) {
-        for (Callback c : mCallbacks) {
-            c.onPostDialWait(this, remainingDigits);
+    void setPostDialWait(final String remainingDigits) {
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onPostDialWait(connection, remainingDigits);
+                }
+            });
         }
     }
 
     /**
      * @hide
      */
-    void onPostDialChar(char nextChar) {
-        for (Callback c : mCallbacks) {
-            c.onPostDialChar(this, nextChar);
+    void onPostDialChar(final char nextChar) {
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onPostDialWait(connection, String.valueOf(nextChar));
+                }
+            });
         }
     }
 
     /**
      * @hide
      */
-    void setVideoState(int videoState) {
+    void setVideoState(final int videoState) {
         mVideoState = videoState;
-        for (Callback c : mCallbacks) {
-            c.onVideoStateChanged(this, videoState);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onVideoStateChanged(connection, videoState);
+                }
+            });
         }
     }
 
     /**
      * @hide
      */
-    void setVideoProvider(VideoProvider videoProvider) {
+    void setVideoProvider(final VideoProvider videoProvider) {
         mVideoProvider = videoProvider;
-        for (Callback c : mCallbacks) {
-            c.onVideoProviderChanged(this, videoProvider);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onVideoProviderChanged(connection, videoProvider);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setIsVoipAudioMode(boolean isVoip) {
+    void setIsVoipAudioMode(final boolean isVoip) {
         mIsVoipAudioMode = isVoip;
-        for (Callback c : mCallbacks) {
-            c.onVoipAudioChanged(this, isVoip);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onVoipAudioChanged(connection, isVoip);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setStatusHints(StatusHints statusHints) {
+    void setStatusHints(final StatusHints statusHints) {
         mStatusHints = statusHints;
-        for (Callback c : mCallbacks) {
-            c.onStatusHintsChanged(this, statusHints);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onStatusHintsChanged(connection, statusHints);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setAddress(Uri address, int presentation) {
+    void setAddress(final Uri address, final int presentation) {
         mAddress = address;
         mAddressPresentation = presentation;
-        for (Callback c : mCallbacks) {
-            c.onAddressChanged(this, address, presentation);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onAddressChanged(connection, address, presentation);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setCallerDisplayName(String callerDisplayName, int presentation) {
+    void setCallerDisplayName(final String callerDisplayName, final int presentation) {
         mCallerDisplayName = callerDisplayName;
         mCallerDisplayNamePresentation = presentation;
-        for (Callback c : mCallbacks) {
-            c.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onCallerDisplayNameChanged(
+                            connection, callerDisplayName, presentation);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
+    void setConferenceableConnections(final List<RemoteConnection> conferenceableConnections) {
         mConferenceableConnections.clear();
         mConferenceableConnections.addAll(conferenceableConnections);
-        for (Callback c : mCallbacks) {
-            c.onConferenceableConnectionsChanged(this, mUnmodifiableconferenceableConnections);
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConferenceableConnectionsChanged(
+                            connection, mUnmodifiableconferenceableConnections);
+                }
+            });
         }
     }
 
     /** @hide */
-    void setConference(RemoteConference conference) {
+    void setConference(final RemoteConference conference) {
         if (mConference != conference) {
             mConference = conference;
-            for (Callback c : mCallbacks) {
-                c.onConferenceChanged(this, conference);
+            for (CallbackRecord record : mCallbackRecords) {
+                final RemoteConnection connection = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onConferenceChanged(connection, conference);
+                    }
+                });
             }
         }
     }
@@ -968,4 +1094,22 @@
     public static RemoteConnection failure(DisconnectCause disconnectCause) {
         return new RemoteConnection(disconnectCause);
     }
+
+    private static final class CallbackRecord extends Callback {
+        private final Callback mCallback;
+        private final Handler mHandler;
+
+        public CallbackRecord(Callback callback, Handler handler) {
+            mCallback = callback;
+            mHandler = handler;
+        }
+
+        public Callback getCallback() {
+            return mCallback;
+        }
+
+        public Handler getHandler() {
+            return mHandler;
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8d6bda8..1431eb8 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -921,7 +921,7 @@
     public void silenceRinger() {
         try {
             if (isServiceConnected()) {
-                getTelecomService().silenceRinger();
+                getTelecomService().silenceRinger(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
@@ -1029,7 +1029,7 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.handlePinMmi(dialString);
+                return service.handlePinMmi(dialString, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#handlePinMmi", e);
             }
@@ -1053,7 +1053,8 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.handlePinMmiForPhoneAccount(accountHandle, dialString);
+                return service.handlePinMmiForPhoneAccount(accountHandle, dialString,
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#handlePinMmi", e);
             }
@@ -1071,7 +1072,7 @@
         ITelecomService service = getTelecomService();
         if (service != null && accountHandle != null) {
             try {
-                return service.getAdnUriForPhoneAccount(accountHandle);
+                return service.getAdnUriForPhoneAccount(accountHandle, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#getAdnUriForPhoneAccount", e);
             }
@@ -1089,7 +1090,7 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                service.cancelMissedCallsNotification();
+                service.cancelMissedCallsNotification(mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#cancelMissedCallsNotification", e);
             }
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 3779d1a..7a82c1b 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -36,13 +36,6 @@
  * {@hide}
  */
 public class VideoCallImpl extends VideoCall {
-    private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
-    private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
-    private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
-    private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
-    private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
-    private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
-    private static final int MSG_CHANGE_VIDEO_QUALITY = 7;
 
     private final IVideoProvider mVideoProvider;
     private final VideoCallListenerBinder mBinder;
@@ -61,7 +54,7 @@
     private final class VideoCallListenerBinder extends IVideoCallback.Stub {
         @Override
         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
-            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
+            mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST,
                     videoProfile).sendToTarget();
         }
 
@@ -72,12 +65,14 @@
             args.arg1 = status;
             args.arg2 = requestProfile;
             args.arg3 = responseProfile;
-            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
+            mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args)
+                    .sendToTarget();
         }
 
         @Override
         public void handleCallSessionEvent(int event) {
-            mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
+            mHandler.obtainMessage(MessageHandler.MSG_HANDLE_CALL_SESSION_EVENT, event)
+                    .sendToTarget();
         }
 
         @Override
@@ -85,28 +80,42 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = width;
             args.arg2 = height;
-            mHandler.obtainMessage(MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
+            mHandler.obtainMessage(MessageHandler.MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
         }
 
         @Override
         public void changeVideoQuality(int videoQuality) {
-            mHandler.obtainMessage(MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0).sendToTarget();
+            mHandler.obtainMessage(MessageHandler.MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0)
+                    .sendToTarget();
         }
 
         @Override
         public void changeCallDataUsage(long dataUsage) {
-            mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget();
+            mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CALL_DATA_USAGE, dataUsage)
+                    .sendToTarget();
         }
 
         @Override
         public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) {
-            mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES,
+            mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CAMERA_CAPABILITIES,
                     cameraCapabilities).sendToTarget();
         }
     }
 
     /** Default handler used to consolidate binder method calls onto a single thread. */
-    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+    private final class MessageHandler extends Handler {
+        private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
+        private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
+        private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
+        private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
+        private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
+        private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
+        private static final int MSG_CHANGE_VIDEO_QUALITY = 7;
+
+        public MessageHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             if (mCallback == null) {
@@ -160,7 +169,8 @@
         }
     };
 
-    /** {@hide} */
+    private Handler mHandler;
+
     VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
@@ -169,13 +179,31 @@
         mVideoProvider.addVideoCallback(mBinder);
     }
 
-    /** {@inheritDoc} */
-    public void registerCallback(VideoCall.Callback callback) {
-        mCallback = callback;
+    public void destroy() {
+        unregisterCallback(mCallback);
     }
 
     /** {@inheritDoc} */
-    public void unregisterCallback() {
+    public void registerCallback(VideoCall.Callback callback) {
+        registerCallback(callback, null);
+    }
+
+    /** {@inheritDoc} */
+    public void registerCallback(VideoCall.Callback callback, Handler handler) {
+        mCallback = callback;
+        if (handler == null) {
+            mHandler = new MessageHandler(Looper.getMainLooper());
+        } else {
+            mHandler = new MessageHandler(handler.getLooper());
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void unregisterCallback(VideoCall.Callback callback) {
+        if (callback != mCallback) {
+            return;
+        }
+
         mCallback = null;
         try {
             mVideoProvider.removeVideoCallback(mBinder);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 49f2aad..bc76f06 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -154,7 +154,7 @@
     /**
      * @see TelecomServiceImpl#silenceRinger
      */
-    void silenceRinger();
+    void silenceRinger(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#isInCall
@@ -184,22 +184,23 @@
     /**
      * @see TelecomServiceImpl#cancelMissedCallsNotification
      */
-    void cancelMissedCallsNotification();
+    void cancelMissedCallsNotification(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#handleMmi
      */
-    boolean handlePinMmi(String dialString);
+    boolean handlePinMmi(String dialString, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#handleMmi
      */
-    boolean handlePinMmiForPhoneAccount(in PhoneAccountHandle accountHandle, String dialString);
+    boolean handlePinMmiForPhoneAccount(in PhoneAccountHandle accountHandle, String dialString,
+            String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getAdnUriForPhoneAccount
      */
-    Uri getAdnUriForPhoneAccount(in PhoneAccountHandle accountHandle);
+    Uri getAdnUriForPhoneAccount(in PhoneAccountHandle accountHandle, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#isTtySupported
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 831a194..299c7c4 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -48,34 +48,148 @@
             ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
 
     /**
+     * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
+     * events from the Sim.
+     * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
+     * effectively disable the "Sim network lock" feature.
+     */
+    public static final String
+            BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
+
+    /**
+     * Flag indicating whether the Phone app should provide a "Dismiss" button on the SIM network
+     * unlock screen. The default value is true. If set to false, there will be *no way* to dismiss
+     * the SIM network unlock screen if you don't enter the correct unlock code. (One important
+     * consequence: there will be no way to make an Emergency Call if your SIM is network-locked and
+     * you don't know the PIN.)
+     */
+    public static final String
+            BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+
+    /** Flag indicating if the phone is a world phone */
+    public static final String BOOL_WORLD_PHONE = "bool_world_phone";
+
+    /**
+     * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
+     * The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
+     * consistent with the regular Dialer, this value should agree with the corresponding values
+     * from config.xml under apps/Contacts.
+     */
+    public static final String
+            BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+
+    /** Flag indicating if dtmf tone type is enabled */
+    public static final String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+
+    /** Flag indicating if auto retry is enabled */
+    public static final String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
+
+    /**
+     * Determine whether we want to play local DTMF tones in a call, or just let the radio/BP handle
+     * playing of the tones.
+     */
+    public static final String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
+
+    /**
+     * If true, show an onscreen "Dial" button in the dialer. In practice this is used on all
+     * platforms, even the ones with hard SEND/END keys, but for maximum flexibility it's controlled
+     * by a flag here (which can be overridden on a per-product basis.)
+     */
+    public static final String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+
+    /** Determines if device implements a noise suppression device for in call audio. */
+    public static final String
+            BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
+
+    /**
+     * Determines if the current device should allow emergency numbers to be logged in the Call Log.
+     * (Some carriers require that emergency calls *not* be logged, presumably to avoid the risk of
+     * accidental redialing from the call log UI. This is a good idea, so the default here is
+     * false.)
+     * <p>
+     * TODO: on the other hand, it might still be useful to have some record of the emergency calls
+     * you've made, or to be able to look up the exact date/time of an emergency call. So perhaps we
+     * <b>should</b> log those calls, but instead fix the call log to disable the "call" button for
+     * emergency numbers.
+     */
+    public static final String
+            BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+
+    /** If true, removes the Voice Privacy option from Call Settings */
+    public static final String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+
+    /** Control whether users can reach the carrier portions of Cellular Network Settings. */
+    public static final String
+            BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+
+    /** Control whether users can edit APNs in Settings. */
+    public static final String BOOL_APN_EXPAND = "bool_apn_expand";
+
+    /** Control whether users can choose a network operator. */
+    public static final String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+
+    /** Used in Cellular Network Settings for preferred network type. */
+    public static final String BOOL_PREFER_2G = "bool_prefer_2g";
+
+    /** Show cdma auto network mode in (glabal) roaming */
+    public static final String BOOL_SHOW_CDMA = "bool_show_cdma";
+
+    /** CDMA activation goes through HFA */
+    public static final String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+
+    /**
+     * CDMA activation goes through OTASP.
+     * <p>
+     * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum
+     * (NONE, HFA, OTASP).
+     */
+    public static final String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+
+    /** Display carrier settings menu if true */
+    public static final String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
+
+    /** Does not display additional call seting for IMS phone based on GSM Phone */
+    public static final String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+
+    /** Show APN Settings for some CDMA carriers */
+    public static final String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+
+    /** After a CDMA conference call is merged, the swap button should be displayed. */
+    public static final String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+
+    /**
+     * Determine whether the voicemail notification is persistent in the notification bar. If true,
+     * the voicemail notifications cannot be dismissed from the notification bar.
+     */
+    public static final String
+            BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+
+    /** For IMS video over LTE calls, determines whether video pause signalling is supported. */
+    public static final String
+            BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+
+    /**
+     * Disables dialing "*228" (OTASP provisioning) on CDMA carriers where it is not supported or is
+     * potentially harmful by locking the SIM to 3G.
+     */
+    public static final String
+            BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+
+    /**
      * Flag specifying whether VoLTE should be available for carrier, independent of carrier
      * provisioning. If false: hard disabled. If true: then depends on carrier provisioning,
      * availability, etc.
      */
     public static final String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
 
-    /**
-     * Flag specifying whether VoLTE availability is based on provisioning.
-     */
+    /** Flag specifying whether VoLTE availability is based on provisioning. */
     public static final String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
 
-    /**
-     * Flag specifying whether VoLTE TTY is supported.
-     */
+    /** Flag specifying whether VoLTE TTY is supported. */
     public static final String BOOL_CARRIER_VOLTE_TTY_SUPPORTED
             = "bool_carrier_volte_tty_supported";
 
     /**
-     * Show APN Settings for some CDMA carriers.
-     */
-    public static final String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
-
-    /**
-     * Control whether users can edit APNs in Settings.
-     */
-    public static final String BOOL_APN_EXPAND = "bool_apn_expand";
-
-    /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
      * RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -86,9 +200,9 @@
     /* The following 3 fields are related to carrier visual voicemail. */
 
     /**
-     *  The carrier number MO sms messages are sent to.
+     * The carrier number MO sms messages are sent to.
      *
-     *  @hide
+     * @hide
      */
     public static final String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
 
@@ -122,17 +236,38 @@
 
     static {
         sDefaults = new Bundle();
+        sDefaults.putBoolean(BOOL_ADDITIONAL_CALL_SETTING, true);
+        sDefaults.putBoolean(BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG, false);
+        sDefaults.putBoolean(BOOL_ALLOW_LOCAL_DTMF_TONES, true);
+        sDefaults.putBoolean(BOOL_APN_EXPAND, true);
+        sDefaults.putBoolean(BOOL_AUTO_RETRY_ENABLED, false);
+        sDefaults.putBoolean(BOOL_CARRIER_SETTINGS_ENABLE, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_AVAILABLE, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_PROVISIONED, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_TTY_SUPPORTED, true);
+        sDefaults.putBoolean(BOOL_DISABLE_CDMA_ACTIVATION_CODE, false);
+        sDefaults.putBoolean(BOOL_DTMF_TYPE_ENABLED, false);
+        sDefaults.putBoolean(BOOL_ENABLE_DIALER_KEY_VIBRATION, true);
+        sDefaults.putBoolean(BOOL_HAS_IN_CALL_NOISE_SUPPRESSION, false);
+        sDefaults.putBoolean(BOOL_HIDE_CARRIER_NETWORK_SETTINGS, false);
+        sDefaults.putBoolean(BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS, false);
+        sDefaults.putBoolean(BOOL_OPERATOR_SELECTION_EXPAND, true);
+        sDefaults.putBoolean(BOOL_PREFER_2G, true);
         sDefaults.putBoolean(BOOL_SHOW_APN_SETTING_CDMA, false);
-        sDefaults.putBoolean(BOOL_APN_EXPAND, true);
-
+        sDefaults.putBoolean(BOOL_SHOW_CDMA, false);
+        sDefaults.putBoolean(BOOL_SHOW_ONSCREEN_DIAL_BUTTON, true);
+        sDefaults.putBoolean(BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS, true);
+        sDefaults.putBoolean(BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS, true);
+        sDefaults.putBoolean(BOOL_SUPPORT_SWAP_AFTER_MERGE, true);
+        sDefaults.putBoolean(BOOL_USE_HFA_FOR_PROVISIONING, false);
+        sDefaults.putBoolean(BOOL_USE_OTASP_FOR_PROVISIONING, false);
+        sDefaults.putBoolean(BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT, false);
+        sDefaults.putBoolean(BOOL_VOICE_PRIVACY_DISABLE, false);
+        sDefaults.putBoolean(BOOL_WORLD_PHONE, false);
         sDefaults.putInt(INT_VOLTE_REPLACEMENT_RAT, 0);
-
+        sDefaults.putInt(INT_VVM_PORT_NUMBER, 0);
         sDefaults.putString(STRING_VVM_DESTINATION_NUMBER, "");
         sDefaults.putString(STRING_VVM_TYPE, "");
-        sDefaults.putInt(INT_VVM_PORT_NUMBER, 0);
     }
 
     /**
@@ -190,10 +325,11 @@
 
     /**
      * Request the carrier config loader to update the cofig for phoneId.
-     *
-     * Depending on simState, the config may be cleared or loaded from config app.
-     * This is only used by SubscriptionInfoUpdater.
-     *
+     * <p>
+     * Depending on simState, the config may be cleared or loaded from config app. This is only used
+     * by SubscriptionInfoUpdater.
+     * </p>
+     * 
      * @hide
      */
     @SystemApi
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cdecb33..303a492 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1104,6 +1104,58 @@
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD;
     }
 
+    /** @hide */
+    public static boolean hasCdma(int radioTechnologyBitmask) {
+        int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
+                | RIL_RADIO_TECHNOLOGY_IS95B
+                | RIL_RADIO_TECHNOLOGY_1xRTT
+                | RIL_RADIO_TECHNOLOGY_EVDO_0
+                | RIL_RADIO_TECHNOLOGY_EVDO_A
+                | RIL_RADIO_TECHNOLOGY_EVDO_B
+                | RIL_RADIO_TECHNOLOGY_EHRPD);
+
+        return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+    }
+
+    /** @hide */
+    public static boolean bitmaskHasTech(int bearerBitmask, int radioTech) {
+        if (bearerBitmask == 0) {
+            return true;
+        } else if (radioTech >= 1) {
+            return ((bearerBitmask & (1 << (radioTech - 1))) != 0);
+        }
+        return false;
+    }
+
+    /** @hide */
+    public static int getBitmaskForTech(int radioTech) {
+        if (radioTech >= 1) {
+            return (1 << (radioTech - 1));
+        }
+        return 0;
+    }
+
+    /** @hide */
+    public static int getBitmaskFromString(String bearerList) {
+        String[] bearers = bearerList.split("\\|");
+        int bearerBitmask = 0;
+        for (String bearer : bearers) {
+            int bearerInt = 0;
+            try {
+                bearerInt = Integer.parseInt(bearer.trim());
+            } catch (NumberFormatException nfe) {
+                return 0;
+            }
+
+            if (bearerInt == 0) {
+                return 0;
+            }
+
+            bearerBitmask |= getBitmaskForTech(bearerInt);
+        }
+        return bearerBitmask;
+    }
+
     /**
      * Returns a merged ServiceState consisting of the base SS with voice settings from the
      * voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned).
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ee7f0ea..d674b31 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3703,7 +3703,7 @@
     @SystemApi
     public void silenceRinger() {
         try {
-            getTelecomService().silenceRinger();
+            getTelecomService().silenceRinger(mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
         }
diff --git a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
index 322b853..30d204f 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
@@ -52,6 +52,11 @@
                 public boolean checkPermission(java.lang.String permission, int pid, int uid) {
                     return true;
                 }
+
+                @Override
+                public String[] getPackagesForUid(int uid) {
+                    return new String[0];
+                }
             };
             ServiceManagerNative.asInterface(BinderInternal.getContextObject())
                     .setPermissionController(pc);
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 7f1e977..4072302 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -164,10 +164,6 @@
                                 com.android.internal.R.styleable.Include_id, View.NO_ID);
                         final int visibility = a.getInt(
                                 com.android.internal.R.styleable.Include_visibility, -1);
-                        final boolean hasWidth = a.hasValue(
-                                com.android.internal.R.styleable.Include_layout_width);
-                        final boolean hasHeight = a.hasValue(
-                                com.android.internal.R.styleable.Include_layout_height);
                         a.recycle();
 
                         // We try to load the layout params set in the <include /> tag. If
@@ -179,19 +175,17 @@
                         // successfully loaded layout params from the <include /> tag,
                         // false means we need to rely on the included layout params.
                         ViewGroup.LayoutParams params = null;
-                        if (hasWidth && hasHeight) {
-                            try {
-                                // ---- START CHANGES
-                                sIsInInclude = true;
-                                // ---- END CHANGES
+                        try {
+                            // ---- START CHANGES
+                            sIsInInclude = true;
+                            // ---- END CHANGES
 
-                                params = group.generateLayoutParams(attrs);
+                            params = group.generateLayoutParams(attrs);
 
-                            } finally {
-                                // ---- START CHANGES
-                                sIsInInclude = false;
-                                // ---- END CHANGES
-                            }
+                        } finally {
+                            // ---- START CHANGES
+                            sIsInInclude = false;
+                            // ---- END CHANGES
                         }
                         if (params == null) {
                             params = group.generateLayoutParams(childAttrs);