Merge "Add missing accessors on GradientDrawable, NinePatchDrawable"
diff --git a/api/current.txt b/api/current.txt
index 5b7800b..0394d56 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11276,6 +11276,7 @@
     method public static int blue(int);
     method public static void colorToHSV(int, float[]);
     method public static int green(int);
+    method public static float luminance(int);
     method public static int parseColor(java.lang.String);
     method public static int red(int);
     method public static int rgb(int, int, int);
@@ -41451,6 +41452,8 @@
     method public void dispatchDraw(android.graphics.Canvas);
     method public void focusCurrentTab(int);
     method public android.view.View getChildTabViewAt(int);
+    method public android.graphics.drawable.Drawable getLeftStripDrawable();
+    method public android.graphics.drawable.Drawable getRightStripDrawable();
     method public int getTabCount();
     method public boolean isStripEnabled();
     method public void onFocusChange(android.view.View, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 875c823..a1aa042 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11613,6 +11613,7 @@
     method public static int blue(int);
     method public static void colorToHSV(int, float[]);
     method public static int green(int);
+    method public static float luminance(int);
     method public static int parseColor(java.lang.String);
     method public static int red(int);
     method public static int rgb(int, int, int);
@@ -44097,6 +44098,8 @@
     method public void dispatchDraw(android.graphics.Canvas);
     method public void focusCurrentTab(int);
     method public android.view.View getChildTabViewAt(int);
+    method public android.graphics.drawable.Drawable getLeftStripDrawable();
+    method public android.graphics.drawable.Drawable getRightStripDrawable();
     method public int getTabCount();
     method public boolean isStripEnabled();
     method public void onFocusChange(android.view.View, boolean);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 964b776..f66a4c7 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 
 import android.app.ActivityManager;
@@ -844,7 +845,7 @@
         return Integer.toString(result);
     }
 
-    // pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
+    // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined}
     private int runSetAppLink() {
         int userId = UserHandle.USER_SYSTEM;
 
@@ -893,6 +894,10 @@
                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
                 break;
 
+            case "always-ask":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+                break;
+
             case "never":
                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
                 break;
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 474154b..2caec369 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -43,6 +43,8 @@
     void clearWindowAnimationFrameStats();
     WindowAnimationFrameStats getWindowAnimationFrameStats();
     void executeShellCommand(String command, in ParcelFileDescriptor fd);
+    void grantRuntimePermission(String packageName, String permission, int userId);
+    void revokeRuntimePermission(String packageName, String permission, int userId);
 
     // Called from the system process.
     oneway void shutdown();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index a8494fb..efed2e0 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -30,6 +30,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
 import android.view.InputEvent;
@@ -846,6 +847,62 @@
     }
 
     /**
+     * Grants a runtime permission to a package for a user.
+     * @param packageName The package to which to grant.
+     * @param permission The permission to grant.
+     * @return Whether granting succeeded.
+     *
+     * @hide
+     */
+    public boolean grantRuntimePermission(String packageName, String permission,
+            UserHandle userHandle) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Granting runtime permission");
+            }
+            // Calling out without a lock held.
+            mUiAutomationConnection.grantRuntimePermission(packageName,
+                    permission, userHandle.getIdentifier());
+            // TODO: The package manager API should return boolean.
+            return true;
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error granting runtime permission", re);
+        }
+        return false;
+    }
+
+    /**
+     * Revokes a runtime permission from a package for a user.
+     * @param packageName The package from which to revoke.
+     * @param permission The permission to revoke.
+     * @return Whether revoking succeeded.
+     *
+     * @hide
+     */
+    public boolean revokeRuntimePermission(String packageName, String permission,
+            UserHandle userHandle) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Revoking runtime permission");
+            }
+            // Calling out without a lock held.
+            mUiAutomationConnection.revokeRuntimePermission(packageName,
+                    permission, userHandle.getIdentifier());
+            // TODO: The package manager API should return boolean.
+            return true;
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error revoking runtime permission", re);
+        }
+        return false;
+    }
+
+    /**
      * Executes a shell command. This method returs a file descriptor that points
      * to the standard output stream. The command execution is similar to running
      * "adb shell <command>" from a host connected to the device.
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 39cd3bc..13e27e2 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -19,6 +19,7 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.Context;
+import android.content.pm.IPackageManager;
 import android.graphics.Bitmap;
 import android.hardware.input.InputManager;
 import android.os.Binder;
@@ -60,6 +61,9 @@
     private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub
             .asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
 
+    private final IPackageManager mPackageManager = IPackageManager.Stub
+            .asInterface(ServiceManager.getService("package"));
+
     private final Object mLock = new Object();
 
     private final Binder mToken = new Binder();
@@ -227,6 +231,38 @@
     }
 
     @Override
+    public void grantRuntimePermission(String packageName, String permission, int userId)
+            throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mPackageManager.grantRuntimePermission(packageName, permission, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void revokeRuntimePermission(String packageName, String permission, int userId)
+            throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mPackageManager.revokeRuntimePermission(packageName, permission, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void executeShellCommand(final String command, final ParcelFileDescriptor sink)
             throws RemoteException {
         synchronized (mLock) {
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 4dbac05..953b051 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 
 import android.os.Parcel;
@@ -199,6 +200,10 @@
                 sb.append("never");
                 break;
 
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK:
+                sb.append("always-ask");
+                break;
+
             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
             default:
                 sb.append("undefined");
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0f936fd..c8e9402 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1073,6 +1073,18 @@
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3;
 
     /**
+     * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
+     * to indicate that this app should always be considered as an ambiguous candidate for
+     * handling the matching Intent even if there are other candidate apps in the "always"
+     * state.  Put another way: if there are any 'always ask' apps in a set of more than
+     * one candidate app, then a disambiguation is *always* presented even if there is
+     * another candidate app with the 'always' state.
+     *
+     * @hide
+     */
+    public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4;
+
+    /**
      * Can be used as the {@code millisecondsToDelay} argument for
      * {@link PackageManager#extendVerificationTimeout}. This is the
      * maximum time {@code PackageManager} waits for the verification
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index d9cff4e..0cc630a 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -16,8 +16,10 @@
 
 package android.widget;
 
-import android.R;
+import com.android.internal.R;
+
 import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -33,21 +35,25 @@
 /**
  *
  * Displays a list of tab labels representing each page in the parent's tab
- * collection. The container object for this widget is
- * {@link android.widget.TabHost TabHost}. When the user selects a tab, this
- * object sends a message to the parent container, TabHost, to tell it to switch
- * the displayed page. You typically won't use many methods directly on this
- * object. The container TabHost is used to add labels, add the callback
- * handler, and manage callbacks. You might call this object to iterate the list
- * of tabs, or to tweak the layout of the tab list, but most methods should be
- * called on the containing TabHost object.
- * 
+ * collection.
+ * <p>
+ * The container object for this widget is {@link android.widget.TabHost TabHost}.
+ * When the user selects a tab, this object sends a message to the parent
+ * container, TabHost, to tell it to switch the displayed page. You typically
+ * won't use many methods directly on this object. The container TabHost is
+ * used to add labels, add the callback handler, and manage callbacks. You
+ * might call this object to iterate the list of tabs, or to tweak the layout
+ * of the tab list, but most methods should be called on the containing TabHost
+ * object.
+ *
  * @attr ref android.R.styleable#TabWidget_divider
  * @attr ref android.R.styleable#TabWidget_tabStripEnabled
  * @attr ref android.R.styleable#TabWidget_tabStripLeft
  * @attr ref android.R.styleable#TabWidget_tabStripRight
  */
 public class TabWidget extends LinearLayout implements OnFocusChangeListener {
+    private final Rect mBounds = new Rect();
+
     private OnTabSelectionChanged mSelectionChangedListener;
 
     // This value will be set to 0 as soon as the first tab is added to TabHost.
@@ -59,9 +65,8 @@
     private boolean mDrawBottomStrips = true;
     private boolean mStripMoved;
 
-    private final Rect mBounds = new Rect();
-
-    // When positive, the widths and heights of tabs will be imposed so that they fit in parent
+    // When positive, the widths and heights of tabs will be imposed so that
+    // they fit in parent.
     private int mImposedTabsHeight = -1;
     private int[] mImposedTabWidths;
 
@@ -81,20 +86,48 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
+                attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes);
 
-        setStripEnabled(a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true));
-        setLeftStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripLeft));
-        setRightStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripRight));
+        mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips);
+
+        // Tests the target SDK version, as set in the Manifest. Could not be
+        // set using styles.xml in a values-v? directory which targets the
+        // current platform SDK version instead.
+        final boolean isTargetSdkDonutOrLower =
+                context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT;
+
+        final boolean hasExplicitLeft = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripLeft);
+        if (hasExplicitLeft) {
+            mLeftStrip = a.getDrawable(R.styleable.TabWidget_tabStripLeft);
+        } else if (isTargetSdkDonutOrLower) {
+            mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left_v4);
+        } else {
+            mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left);
+        }
+
+        final boolean hasExplicitRight = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripRight);
+        if (hasExplicitRight) {
+            mRightStrip = a.getDrawable(R.styleable.TabWidget_tabStripRight);
+        } else if (isTargetSdkDonutOrLower) {
+            mRightStrip = context.getDrawable(R.drawable.tab_bottom_right_v4);
+        } else {
+            mRightStrip = context.getDrawable(R.drawable.tab_bottom_right);
+        }
 
         a.recycle();
 
-        initTabWidget();
+        setChildrenDrawingOrderEnabled(true);
+
+        // Deal with focus, as we don't want the focus to go by default
+        // to a tab other than the current tab
+        setFocusable(true);
+        setOnFocusChangeListener(this);
     }
 
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         mStripMoved = true;
+
         super.onSizeChanged(w, h, oldw, oldh);
     }
 
@@ -115,44 +148,8 @@
         }
     }
 
-    private void initTabWidget() {
-        setChildrenDrawingOrderEnabled(true);
-
-        final Context context = mContext;
-
-        // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
-        // in a values-v? directory which targets the current platform Sdk version instead.
-        if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
-            // Donut apps get old color scheme
-            if (mLeftStrip == null) {
-                mLeftStrip = context.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_left_v4);
-            }
-            if (mRightStrip == null) {
-                mRightStrip = context.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_right_v4);
-            }
-        } else {
-            // Use modern color scheme for Eclair and beyond
-            if (mLeftStrip == null) {
-                mLeftStrip = context.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_left);
-            }
-            if (mRightStrip == null) {
-                mRightStrip = context.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_right);
-            }
-        }
-
-        // Deal with focus, as we don't want the focus to go by default
-        // to a tab other than the current tab
-        setFocusable(true);
-        setOnFocusChangeListener(this);
-    }
-
     @Override
-    void measureChildBeforeLayout(View child, int childIndex,
-            int widthMeasureSpec, int totalWidth,
+    void measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth,
             int heightMeasureSpec, int totalHeight) {
         if (!isMeasureWithLargestChildEnabled() && mImposedTabsHeight >= 0) {
             widthMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -209,7 +206,8 @@
             }
         }
 
-        // Measure again, this time with imposed tab widths and respecting initial spec request
+        // Measure again, this time with imposed tab widths and respecting
+        // initial spec request.
         super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
     }
 
@@ -225,7 +223,8 @@
 
     /**
      * Returns the number of tab indicator views.
-     * @return the number of tab indicator views.
+     *
+     * @return the number of tab indicator views
      */
     public int getTabCount() {
         return getChildCount();
@@ -233,65 +232,104 @@
 
     /**
      * Sets the drawable to use as a divider between the tab indicators.
+     *
      * @param drawable the divider drawable
+     * @attr ref android.R.styleable#TabWidget_divider
      */
     @Override
-    public void setDividerDrawable(Drawable drawable) {
+    public void setDividerDrawable(@Nullable Drawable drawable) {
         super.setDividerDrawable(drawable);
     }
 
     /**
      * Sets the drawable to use as a divider between the tab indicators.
-     * @param resId the resource identifier of the drawable to use as a
-     * divider.
+     *
+     * @param resId the resource identifier of the drawable to use as a divider
+     * @attr ref android.R.styleable#TabWidget_divider
      */
     public void setDividerDrawable(@DrawableRes int resId) {
         setDividerDrawable(mContext.getDrawable(resId));
     }
-    
+
     /**
-     * Sets the drawable to use as the left part of the strip below the
-     * tab indicators.
+     * Sets the drawable to use as the left part of the strip below the tab
+     * indicators.
+     *
      * @param drawable the left strip drawable
+     * @see #getLeftStripDrawable()
+     * @attr ref android.R.styleable#TabWidget_tabStripLeft
      */
-    public void setLeftStripDrawable(Drawable drawable) {
+    public void setLeftStripDrawable(@Nullable Drawable drawable) {
         mLeftStrip = drawable;
         requestLayout();
         invalidate();
     }
 
     /**
-     * Sets the drawable to use as the left part of the strip below the
-     * tab indicators.
-     * @param resId the resource identifier of the drawable to use as the
-     * left strip drawable
+     * Sets the drawable to use as the left part of the strip below the tab
+     * indicators.
+     *
+     * @param resId the resource identifier of the drawable to use as the left
+     *              strip drawable
+     * @see #getLeftStripDrawable()
+     * @attr ref android.R.styleable#TabWidget_tabStripLeft
      */
     public void setLeftStripDrawable(@DrawableRes int resId) {
         setLeftStripDrawable(mContext.getDrawable(resId));
     }
 
     /**
-     * Sets the drawable to use as the right part of the strip below the
-     * tab indicators.
-     * @param drawable the right strip drawable
+     * @return the drawable used as the left part of the strip below the tab
+     *         indicators, may be {@code null}
+     * @see #setLeftStripDrawable(int)
+     * @see #setLeftStripDrawable(Drawable)
+     * @attr ref android.R.styleable#TabWidget_tabStripLeft
      */
-    public void setRightStripDrawable(Drawable drawable) {
+    @Nullable
+    public Drawable getLeftStripDrawable() {
+        return mLeftStrip;
+    }
+
+    /**
+     * Sets the drawable to use as the right part of the strip below the tab
+     * indicators.
+     *
+     * @param drawable the right strip drawable
+     * @see #getRightStripDrawable()
+     * @attr ref android.R.styleable#TabWidget_tabStripRight
+     */
+    public void setRightStripDrawable(@Nullable Drawable drawable) {
         mRightStrip = drawable;
         requestLayout();
         invalidate();
     }
 
     /**
-     * Sets the drawable to use as the right part of the strip below the
-     * tab indicators.
-     * @param resId the resource identifier of the drawable to use as the
-     * right strip drawable
+     * Sets the drawable to use as the right part of the strip below the tab
+     * indicators.
+     *
+     * @param resId the resource identifier of the drawable to use as the right
+     *              strip drawable
+     * @see #getRightStripDrawable()
+     * @attr ref android.R.styleable#TabWidget_tabStripRight
      */
     public void setRightStripDrawable(@DrawableRes int resId) {
         setRightStripDrawable(mContext.getDrawable(resId));
     }
 
     /**
+     * @return the drawable used as the right part of the strip below the tab
+     *         indicators, may be {@code null}
+     * @see #setRightStripDrawable(int)
+     * @see #setRightStripDrawable(Drawable)
+     * @attr ref android.R.styleable#TabWidget_tabStripRight
+     */
+    @Nullable
+    public Drawable getRightStripDrawable() {
+        return mRightStrip;
+    }
+
+    /**
      * Controls whether the bottom strips on the tab indicators are drawn or
      * not.  The default is to draw them.  If the user specifies a custom
      * view for the tab indicators, then the TabHost class calls this method
@@ -360,13 +398,14 @@
 
     /**
      * Sets the current tab.
+     * <p>
      * This method is used to bring a tab to the front of the Widget,
      * and is used to post to the rest of the UI that a different tab
      * has been brought to the foreground.
-     *
+     * <p>
      * Note, this is separate from the traditional "focus" that is
      * employed from the view logic.
-     *
+     * <p>
      * For instance, if we have a list in a tabbed view, a user may be
      * navigating up and down the list, moving the UI focus (orange
      * highlighting) through the list items.  The cursor movement does
@@ -374,16 +413,15 @@
      * scrolled through is all on the same tab.  The selected tab only
      * changes when we navigate between tabs (moving from the list view
      * to the next tabbed view, in this example).
-     *
+     * <p>
      * To move both the focus AND the selected tab at once, please use
      * {@link #setCurrentTab}. Normally, the view logic takes care of
      * adjusting the focus, so unless you're circumventing the UI,
      * you'll probably just focus your interest here.
      *
-     *  @param index The tab that you want to indicate as the selected
-     *  tab (tab brought to the front of the widget)
-     *
-     *  @see #focusCurrentTab
+     * @param index the index of the tab that you want to indicate as the
+     *              selected tab (tab brought to the front of the widget)
+     * @see #focusCurrentTab
      */
     public void setCurrentTab(int index) {
         if (index < 0 || index >= getTabCount() || index == mSelectedTab) {
@@ -473,7 +511,7 @@
 
         final int count = getTabCount();
         for (int i = 0; i < count; i++) {
-            View child = getChildTabViewAt(i);
+            final View child = getChildTabViewAt(i);
             child.setEnabled(enabled);
         }
     }
@@ -482,8 +520,7 @@
     public void addView(View child) {
         if (child.getLayoutParams() == null) {
             final LinearLayout.LayoutParams lp = new LayoutParams(
-                    0,
-                    ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
+                    0, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
             lp.setMargins(0, 0, 0, 0);
             child.setLayoutParams(lp);
         }
@@ -507,13 +544,13 @@
     }
 
     /**
-     * Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
+     * Provides a way for {@link TabHost} to be notified that the user clicked
+     * on a tab indicator.
      */
     void setTabSelectionListener(OnTabSelectionChanged listener) {
         mSelectionChangedListener = listener;
     }
 
-    /** {@inheritDoc} */
     public void onFocusChange(View v, boolean hasFocus) {
         if (v == this && hasFocus && getTabCount() > 0) {
             getChildTabViewAt(mSelectedTab).requestFocus();
@@ -540,7 +577,6 @@
 
     // registered with each tab indicator so we can notify tab host
     private class TabClickListener implements OnClickListener {
-
         private final int mTabIndex;
 
         private TabClickListener(int tabIndex) {
@@ -553,17 +589,18 @@
     }
 
     /**
-     * Let {@link TabHost} know that the user clicked on a tab indicator.
+     * Lets {@link TabHost} know that the user clicked on a tab indicator.
      */
-    static interface OnTabSelectionChanged {
+    interface OnTabSelectionChanged {
         /**
          * Informs the TabHost which tab was selected. It also indicates
          * if the tab was clicked/pressed or just focused into.
          *
          * @param tabIndex index of the tab that was selected
-         * @param clicked whether the selection changed due to a touch/click
-         * or due to focus entering the tab through navigation. Pass true
-         * if it was due to a press/click and false otherwise.
+         * @param clicked whether the selection changed due to a touch/click or
+         *                due to focus entering the tab through navigation.
+         *                {@code true} if it was due to a press/click and
+         *                {@code false} otherwise.
          */
         void onTabSelectionChanged(int tabIndex, boolean clicked);
     }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 33595f2..508cb01 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -4032,7 +4032,7 @@
             // dark or the light button frame.
             TypedValue value = new TypedValue();
             getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
-            if (Color.brightness(value.data) < 0.5) {
+            if (Color.luminance(value.data) < 0.5) {
                 nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
                         R.layout.non_client_decor_dark, null);
             } else {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9d0636a..f190d8c 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -294,6 +294,29 @@
     }
 
     /**
+     * Removes value from given array if present, providing set-like behavior.
+     */
+    public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
+        if (cur == null) {
+            return null;
+        }
+        final int N = cur.length;
+        for (int i = 0; i < N; i++) {
+            if (Objects.equals(cur[i], val)) {
+                String[] ret = new String[N - 1];
+                if (i > 0) {
+                    System.arraycopy(cur, 0, ret, 0, i);
+                }
+                if (i < (N - 1)) {
+                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);
+                }
+                return ret;
+            }
+        }
+        return cur;
+    }
+
+    /**
      * Adds value to given array if not already present, providing set-like
      * behavior.
      */
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 2e3eec5..c627297 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -113,89 +113,21 @@
     }
 
     /**
-     * Returns the hue component of a color int.
-     * 
-     * @return A value between 0.0f and 1.0f
-     * 
-     * @hide Pending API council
-     */
-    public static float hue(@ColorInt int color) {
-        int r = (color >> 16) & 0xFF;
-        int g = (color >> 8) & 0xFF;
-        int b = color & 0xFF;
-
-        int V = Math.max(b, Math.max(r, g));
-        int temp = Math.min(b, Math.min(r, g));
-
-        float H;
-
-        if (V == temp) {
-            H = 0;
-        } else {
-            final float vtemp = (float) (V - temp);
-            final float cr = (V - r) / vtemp;
-            final float cg = (V - g) / vtemp;
-            final float cb = (V - b) / vtemp;
-
-            if (r == V) {
-                H = cb - cg;
-            } else if (g == V) {
-                H = 2 + cr - cb;
-            } else {
-                H = 4 + cg - cr;
-            }
-
-            H /= 6.f;
-            if (H < 0) {
-                H++;
-            }
-        }
-
-        return H;
-    }
-
-    /**
-     * Returns the saturation component of a color int.
-     * 
-     * @return A value between 0.0f and 1.0f
-     * 
-     * @hide Pending API council
-     */
-    public static float saturation(@ColorInt int color) {
-        int r = (color >> 16) & 0xFF;
-        int g = (color >> 8) & 0xFF;
-        int b = color & 0xFF;
-
-
-        int V = Math.max(b, Math.max(r, g));
-        int temp = Math.min(b, Math.min(r, g));
-
-        float S;
-
-        if (V == temp) {
-            S = 0;
-        } else {
-            S = (V - temp) / (float) V;
-        }
-
-        return S;
-    }
-
-    /**
-     * Returns the brightness component of a color int.
+     * Returns the relative luminance of a color.
+     * <p>
+     * Assumes sRGB encoding. Based on the formula for relative luminance
+     * defined in WCAG 2.0, W3C Recommendation 11 December 2008.
      *
-     * @return A value between 0.0f and 1.0f
-     *
-     * @hide Pending API council
+     * @return a value between 0 (darkest black) and 1 (lightest white)
      */
-    public static float brightness(@ColorInt int color) {
-        int r = (color >> 16) & 0xFF;
-        int g = (color >> 8) & 0xFF;
-        int b = color & 0xFF;
-
-        int V = Math.max(b, Math.max(r, g));
-
-        return (V / 255.f);
+    public static float luminance(@ColorInt int color) {
+        double red = Color.red(color) / 255.0;
+        red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
+        double green = Color.green(color) / 255.0;
+        green = green < 0.03928 ? green / 12.92 : Math.pow((green + 0.055) / 1.055, 2.4);
+        double blue = Color.blue(color) / 255.0;
+        blue = blue < 0.03928 ? blue / 12.92 : Math.pow((blue + 0.055) / 1.055, 2.4);
+        return (float) ((0.2126 * red) + (0.7152 * green) + (0.0722 * blue));
     }
 
     /**
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ba7974c..daf42fb 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -261,12 +261,6 @@
     <!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
     <integer name="doze_pulse_duration_in_pickup">300</integer>
 
-    <!-- Doze: pulse parameter - delay to wait for the screen to wake up -->
-    <integer name="doze_pulse_delay_in">200</integer>
-
-    <!-- Doze: pulse parameter - delay to wait for the screen to wake up after a pickup -->
-    <integer name="doze_pulse_delay_in_pickup">200</integer>
-
     <!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
     <integer name="doze_pulse_duration_visible">3000</integer>
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index fe876d7..7f68e29 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -159,7 +159,9 @@
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Async playback only available from system UID.");
             }
-
+            if (UserHandle.ALL.equals(user)) {
+                user = UserHandle.OWNER;
+            }
             mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a6cea62..a55256d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -171,13 +171,7 @@
     // on-screen navigation buttons
     protected NavigationBarView mNavigationBarView = null;
 
-    protected Boolean mScreenOn;
-
-    // The second field is a bit different from the first one because it only listens to screen on/
-    // screen of events from Keyguard. We need this so we don't have a race condition with the
-    // broadcast. In the future, we should remove the first field altogether and rename the second
-    // field.
-    protected boolean mScreenOnFromKeyguard;
+    protected boolean mDeviceInteractive;
 
     protected boolean mVisible;
 
@@ -1722,7 +1716,7 @@
 
     protected void updateVisibleToUser() {
         boolean oldVisibleToUser = mVisibleToUser;
-        mVisibleToUser = mVisible && mScreenOnFromKeyguard;
+        mVisibleToUser = mVisible && mDeviceInteractive;
 
         if (oldVisibleToUser != mVisibleToUser) {
             handleVisibleToUserChanged(mVisibleToUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6b167b4..5a2fa3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -50,8 +50,6 @@
         pw.print("    getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
         pw.print("    getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
         pw.print("    getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
-        pw.print("    getPulseInDelay(pickup=false): "); pw.println(getPulseInDelay(false));
-        pw.print("    getPulseInDelay(pickup=true): "); pw.println(getPulseInDelay(true));
         pw.print("    getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
@@ -80,12 +78,6 @@
                 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
     }
 
-    public int getPulseInDelay(boolean pickup) {
-        return pickup
-                ? getInt("doze.pulse.delay.in.pickup", R.integer.doze_pulse_delay_in_pickup)
-                : getInt("doze.pulse.delay.in", R.integer.doze_pulse_delay_in);
-    }
-
     public int getPulseVisibleDuration() {
         return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 3e17328..86b8972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -100,6 +100,16 @@
         mHandler.post(mPulseIn);
     }
 
+    public void onScreenTurnedOn() {
+        if (isPulsing()) {
+            final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
+            startScrimAnimation(true /* inFront */, 0f,
+                    mDozeParameters.getPulseInDuration(pickup),
+                    pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
+                    mPulseInFinished);
+        }
+    }
+
     public boolean isPulsing() {
         return mPulseCallback != null;
     }
@@ -138,12 +148,11 @@
 
     private void startScrimAnimation(final boolean inFront, float target, long duration,
             Interpolator interpolator) {
-        startScrimAnimation(inFront, target, duration, interpolator, 0 /* delay */,
-                null /* endRunnable */);
+        startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
     }
 
     private void startScrimAnimation(final boolean inFront, float target, long duration,
-            Interpolator interpolator, long delay, final Runnable endRunnable) {
+            Interpolator interpolator, final Runnable endRunnable) {
         Animator current = getCurrentAnimator(inFront);
         if (current != null) {
             float currentTarget = getCurrentTarget(inFront);
@@ -162,7 +171,6 @@
         });
         anim.setInterpolator(interpolator);
         anim.setDuration(duration);
-        anim.setStartDelay(delay);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -222,12 +230,6 @@
                     + DozeLog.pulseReasonToString(mPulseReason));
             if (!mDozing) return;
             DozeLog.tracePulseStart(mPulseReason);
-            final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
-            startScrimAnimation(true /* inFront */, 0f,
-                    mDozeParameters.getPulseInDuration(pickup),
-                    pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
-                    mDozeParameters.getPulseInDelay(pickup),
-                    mPulseInFinished);
 
             // Signal that the pulse is ready to turn the screen on and draw.
             pulseStarted();
@@ -249,7 +251,7 @@
             if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
             if (!mDozing) return;
             startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
-                    mPulseOutInterpolator, 0 /* delay */, mPulseOutFinished);
+                    mPulseOutInterpolator, mPulseOutFinished);
         }
     };
 
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 8c58fc5..710c335 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -918,7 +918,7 @@
     }
 
     private int getFalsingThreshold() {
-        float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+        float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
         return (int) (mQsFalsingThreshold * factor);
     }
 
@@ -2075,7 +2075,7 @@
 
     @Override
     public float getAffordanceFalsingFactor() {
-        return mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+        return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
     }
 
     @Override
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 5995fe1..9cd6ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -391,7 +391,7 @@
                     || forceCancel;
             DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                     mStatusBar.isFalsingThresholdNeeded(),
-                    mStatusBar.isScreenOnComingFromTouch());
+                    mStatusBar.isWakeUpComingFromTouch());
                     // Log collapse gesture if on lock screen.
                     if (!expand && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
                         float displayDensity = mStatusBar.getDisplayDensity();
@@ -420,7 +420,7 @@
     }
 
     private int getFalsingThreshold() {
-        float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+        float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
         return (int) (mUnlockFalsingThreshold * factor);
     }
 
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 52acbf8..0635847 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -282,8 +282,8 @@
     private StatusBarWindowManager mStatusBarWindowManager;
     private UnlockMethodCache mUnlockMethodCache;
     private DozeServiceHost mDozeServiceHost;
-    private boolean mScreenOnComingFromTouch;
-    private PointF mScreenOnTouchLocation;
+    private boolean mWakeUpComingFromTouch;
+    private PointF mWakeUpTouchLocation;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
@@ -1933,8 +1933,8 @@
         return mNotificationPanel.isQsExpanded();
     }
 
-    public boolean isScreenOnComingFromTouch() {
-        return mScreenOnComingFromTouch;
+    public boolean isWakeUpComingFromTouch() {
+        return mWakeUpComingFromTouch;
     }
 
     public boolean isFalsingThresholdNeeded() {
@@ -2494,7 +2494,7 @@
     private void checkBarMode(int mode, int windowState, BarTransitions transitions,
             boolean noAnimation) {
         final boolean powerSave = mBatteryController.isPowerSave();
-        final boolean anim = !noAnimation && (mScreenOn == null || mScreenOn)
+        final boolean anim = !noAnimation && mDeviceInteractive
                 && windowState != WINDOW_STATE_HIDDEN && !powerSave;
         if (powerSave && getBarState() == StatusBarState.SHADE) {
             mode = MODE_WARNING;
@@ -2902,14 +2902,12 @@
                 }
             }
             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                mScreenOn = false;
                 notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOff();
                 finishBarAnimations();
                 resetUserExpandedStates();
             }
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
-                mScreenOn = true;
                 notifyNavigationBarScreenOn(true);
             }
         }
@@ -3363,7 +3361,7 @@
         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         setBarState(StatusBarState.KEYGUARD);
         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
-        if (!mScreenOnFromKeyguard) {
+        if (!mDeviceInteractive) {
 
             // If the screen is off already, we need to disable touch events because these might
             // collapse the panel after we expanded it, and thus we would end up with a blank
@@ -3583,7 +3581,7 @@
     private void updateDozingState() {
         boolean animate = !mDozing && mDozeScrimController.isPulsing();
         mNotificationPanel.setDozing(mDozing, animate);
-        mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation);
+        mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
         mScrimController.setDozing(mDozing);
         mDozeScrimController.setDozing(mDozing, animate);
     }
@@ -3636,7 +3634,7 @@
     }
 
     public boolean onSpacePressed() {
-        if (mScreenOn != null && mScreenOn
+        if (mDeviceInteractive
                 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
             animateCollapsePanels(
                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
@@ -3846,16 +3844,16 @@
         disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
     }
 
-    public void onScreenTurnedOff() {
-        mScreenOnFromKeyguard = false;
-        mScreenOnComingFromTouch = false;
-        mScreenOnTouchLocation = null;
+    public void onFinishedGoingToSleep() {
+        mDeviceInteractive = false;
+        mWakeUpComingFromTouch = false;
+        mWakeUpTouchLocation = null;
         mStackScroller.setAnimationsEnabled(false);
         updateVisibleToUser();
     }
 
-    public void onScreenTurnedOn() {
-        mScreenOnFromKeyguard = true;
+    public void onStartedWakingUp() {
+        mDeviceInteractive = true;
         mStackScroller.setAnimationsEnabled(true);
         mNotificationPanel.setTouchDisabled(false);
         updateVisibleToUser();
@@ -3865,6 +3863,10 @@
         mNotificationPanel.onScreenTurningOn();
     }
 
+    public void onScreenTurnedOn() {
+        mDozeScrimController.onScreenTurnedOn();
+    }
+
     /**
      * This handles long-press of both back and recents.  They are
      * handled together to capture them both being long-pressed
@@ -3979,8 +3981,8 @@
         if (mDozing && mDozeScrimController.isPulsing()) {
             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
             pm.wakeUp(time, "com.android.systemui:NODOZE");
-            mScreenOnComingFromTouch = true;
-            mScreenOnTouchLocation = new PointF(event.getX(), event.getY());
+            mWakeUpComingFromTouch = true;
+            mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
             mNotificationPanel.setTouchDisabled(false);
             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9543f93..9d47713 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -162,14 +162,14 @@
 
     public void onFinishedGoingToSleep() {
         mDeviceInteractive = false;
-        mPhoneStatusBar.onScreenTurnedOff();
+        mPhoneStatusBar.onFinishedGoingToSleep();
         mBouncer.onScreenTurnedOff();
     }
 
     public void onStartedWakingUp() {
         mDeviceInteractive = true;
         mDeviceWillWakeUp = false;
-        mPhoneStatusBar.onScreenTurnedOn();
+        mPhoneStatusBar.onStartedWakingUp();
     }
 
     public void onScreenTurningOn() {
@@ -184,6 +184,7 @@
             animateScrimControllerKeyguardFadingOut(0, 200);
             updateStates();
         }
+        mPhoneStatusBar.onScreenTurnedOn();
     }
 
     public void onScreenTurnedOff() {
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 6b30183..82c1aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -653,7 +653,7 @@
 
     @Override
     public float getFalsingThresholdFactor() {
-        return mPhoneStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+        return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
     }
 
     public View getChildAtPosition(MotionEvent ev) {
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c13401f..b766894 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -157,7 +157,7 @@
         mFactoryTest = factoryTest;
 
         // Let the package manager query for the sync adapters for a given authority
-        // as we grant default permissions to sync adapters for specifix authorities.
+        // as we grant default permissions to sync adapters for specific authorities.
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
         packageManagerInternal.setSyncAdapterPackagesprovider(
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 18407c9..52d0928 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -88,4 +88,10 @@
         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                 == PermissionInfo.PROTECTION_DANGEROUS;
     }
+
+    public boolean isDevelopment() {
+        return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                == PermissionInfo.PROTECTION_SIGNATURE
+                && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 71a2d59..d2a70df 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -296,7 +296,7 @@
             PackageParser.Package storagePackage = getDefaultProviderAuthorityPackageLPr(
                     "com.android.externalstorage.documents", userId);
             if (storagePackage != null) {
-                grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, true, userId);
             }
 
             // CertInstaller
@@ -360,7 +360,7 @@
             PackageParser.Package cbrPackage =
                     getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId);
             if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
-                grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, false, userId);
+                grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, userId);
             }
 
             // Calendar
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0a3097..e8ec8b9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -56,6 +56,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.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 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;
@@ -3451,14 +3452,14 @@
         }
     }
 
-    private static void enforceDeclaredAsUsedAndRuntimePermission(PackageParser.Package pkg,
+    private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(PackageParser.Package pkg,
             BasePermission bp) {
         int index = pkg.requestedPermissions.indexOf(bp.name);
         if (index == -1) {
             throw new SecurityException("Package " + pkg.packageName
                     + " has not requested permission " + bp.name);
         }
-        if (!bp.isRuntime()) {
+        if (!bp.isRuntime() && !bp.isDevelopment()) {
             throw new SecurityException("Permission " + bp.name
                     + " is not a changeable permission type");
         }
@@ -3492,7 +3493,7 @@
                 throw new IllegalArgumentException("Unknown permission: " + name);
             }
 
-            enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
+            enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
 
             uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
             sb = (SettingBase) pkg.mExtras;
@@ -3508,6 +3509,16 @@
                         + name + " for package: " + packageName);
             }
 
+            if (bp.isDevelopment()) {
+                // Development permissions must be handled specially, since they are not
+                // normal runtime permissions.  For now they apply to all users.
+                if (permissionsState.grantInstallPermission(bp) !=
+                        PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                    scheduleWriteSettingsLocked();
+                }
+                return;
+            }
+
             final int result = permissionsState.grantRuntimePermission(bp, userId);
             switch (result) {
                 case PermissionsState.PERMISSION_OPERATION_FAILURE: {
@@ -3576,7 +3587,7 @@
                 throw new IllegalArgumentException("Unknown permission: " + name);
             }
 
-            enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
+            enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
 
             SettingBase sb = (SettingBase) pkg.mExtras;
             if (sb == null) {
@@ -3591,6 +3602,16 @@
                         + name + " for package: " + packageName);
             }
 
+            if (bp.isDevelopment()) {
+                // Development permissions must be handled specially, since they are not
+                // normal runtime permissions.  For now they apply to all users.
+                if (permissionsState.revokeInstallPermission(bp) !=
+                        PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                    scheduleWriteSettingsLocked();
+                }
+                return;
+            }
+
             if (permissionsState.revokeRuntimePermission(bp, userId) ==
                     PermissionsState.PERMISSION_OPERATION_FAILURE) {
                 return;
@@ -3818,21 +3839,6 @@
         return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
     }
 
-    void grantInstallPermissionLPw(String permission, PackageParser.Package pkg) {
-        BasePermission bp = mSettings.mPermissions.get(permission);
-        if (bp == null) {
-            throw new SecurityException("Missing " + permission + " permission");
-        }
-
-        SettingBase sb = (SettingBase) pkg.mExtras;
-        PermissionsState permissionsState = sb.getPermissionsState();
-
-        if (permissionsState.grantInstallPermission(bp) !=
-                PermissionsState.PERMISSION_OPERATION_FAILURE) {
-            scheduleWriteSettingsLocked();
-        }
-    }
-
     @Override
     public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
         mContext.enforceCallingOrSelfPermission(
@@ -4720,6 +4726,7 @@
         ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> alwaysAskList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
 
@@ -4756,6 +4763,11 @@
                             Slog.i(TAG, "  + never: " + info.activityInfo.packageName);
                         }
                         neverList.add(info);
+                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
+                        if (DEBUG_DOMAIN_VERIFICATION) {
+                            Slog.i(TAG, "  + always-ask: " + info.activityInfo.packageName);
+                        }
+                        alwaysAskList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
                             status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
@@ -4765,6 +4777,10 @@
                     }
                 }
             }
+
+            // We'll want to include browser possibilities in a few cases
+            boolean includeBrowser = false;
+
             // First try to add the "always" resolution(s) for the current user, if any
             if (alwaysList.size() > 0) {
                 result.addAll(alwaysList);
@@ -4773,7 +4789,7 @@
                     == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
                 result.add(xpDomainInfo.resolveInfo);
             } else {
-                // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
+                // Add all undefined apps as we want them to appear in the disambiguation dialog.
                 result.addAll(undefinedList);
                 if (xpDomainInfo != null && (
                         xpDomainInfo.bestDomainVerificationStatus
@@ -4782,7 +4798,25 @@
                         == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK)) {
                     result.add(xpDomainInfo.resolveInfo);
                 }
-                // Also add Browsers (all of them or only the default one)
+                includeBrowser = true;
+            }
+
+            // The presence of any 'always ask' alternatives means we'll also offer browsers.
+            // If there were 'always' entries their preferred order has been set, so we also
+            // back that off to make the alternatives equivalent
+            if (alwaysAskList.size() > 0) {
+                for (ResolveInfo i : result) {
+                    i.preferredOrder = 0;
+                }
+                result.addAll(alwaysAskList);
+                includeBrowser = true;
+            }
+
+            if (includeBrowser) {
+                // Also add browsers (all of them or only the default one)
+                if (DEBUG_DOMAIN_VERIFICATION) {
+                    Slog.v(TAG, "   ...including browsers in candidate set");
+                }
                 if ((matchFlags & MATCH_ALL) != 0) {
                     result.addAll(matchAllList);
                 } else {
@@ -14876,6 +14910,7 @@
                 pw.println("    version: print database version info");
                 pw.println("    write: write current settings now");
                 pw.println("    installs: details about install sessions");
+                pw.println("    check-permission <permission> <package> [<user>]: does pkg hold perm?");
                 pw.println("    <package.name>: info about given package");
                 return;
             } else if ("--checkin".equals(opt)) {
@@ -14897,6 +14932,31 @@
                 // When dumping a single package, we always dump all of its
                 // filter information since the amount of data will be reasonable.
                 dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+            } else if ("check-permission".equals(cmd)) {
+                if (opti >= args.length) {
+                    pw.println("Error: check-permission missing permission argument");
+                    return;
+                }
+                String perm = args[opti];
+                opti++;
+                if (opti >= args.length) {
+                    pw.println("Error: check-permission missing package argument");
+                    return;
+                }
+                String pkg = args[opti];
+                opti++;
+                int user = UserHandle.getUserId(Binder.getCallingUid());
+                if (opti < args.length) {
+                    try {
+                        user = Integer.parseInt(args[opti]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Error: check-permission user argument is not a number: "
+                                + args[opti]);
+                        return;
+                    }
+                }
+                pw.println(checkPermission(perm, pkg, user));
+                return;
             } else if ("l".equals(cmd) || "libraries".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_LIBS);
             } else if ("f".equals(cmd) || "features".equals(cmd)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bd7ec31..943e649 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3952,7 +3952,7 @@
 
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
             ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
-            Date date, List<UserInfo> users) {
+            Date date, List<UserInfo> users, boolean dumpAll) {
         if (checkinTag != null) {
             pw.print(checkinTag);
             pw.print(",");
@@ -4154,7 +4154,7 @@
                     pw.print(", COSTS_MONEY");
                 }
                 if ((perm.info.flags&PermissionInfo.FLAG_HIDDEN) != 0) {
-                    pw.print(", COSTS_HIDDEN");
+                    pw.print(", HIDDEN");
                 }
                 if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
                     pw.print(", INSTALLED");
@@ -4163,7 +4163,21 @@
             }
         }
 
-        if (ps.sharedUser == null || permissionNames != null) {
+        if ((permissionNames != null || dumpAll) && ps.pkg.requestedPermissions != null
+                && ps.pkg.requestedPermissions.size() > 0) {
+            final ArrayList<String> perms = ps.pkg.requestedPermissions;
+            pw.print(prefix); pw.println("  requested permissions:");
+            for (int i=0; i<perms.size(); i++) {
+                String perm = perms.get(i);
+                if (permissionNames != null
+                        && !permissionNames.contains(perm)) {
+                    continue;
+                }
+                pw.print(prefix); pw.print("    "); pw.println(perm);
+            }
+        }
+
+        if (ps.sharedUser == null || permissionNames != null || dumpAll) {
             PermissionsState permissionsState = ps.getPermissionsState();
             dumpInstallPermissionsLPr(pw, prefix + "  ", permissionNames, permissionsState);
         }
@@ -4190,7 +4204,7 @@
                 PermissionsState permissionsState = ps.getPermissionsState();
                 dumpGidsLPr(pw, prefix + "    ", permissionsState.computeGids(user.id));
                 dumpRuntimePermissionsLPr(pw, prefix + "    ", permissionNames, permissionsState
-                        .getRuntimePermissionStates(user.id));
+                        .getRuntimePermissionStates(user.id), dumpAll);
             }
 
             if (permissionNames == null) {
@@ -4238,11 +4252,12 @@
                 pw.println("Packages:");
                 printedSomething = true;
             }
-            dumpPackageLPr(pw, "  ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users);
+            dumpPackageLPr(pw, "  ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users,
+                    packageName != null);
         }
 
         printedSomething = false;
-        if (!checkin && mRenamedPackages.size() > 0 && permissionNames == null) {
+        if (mRenamedPackages.size() > 0 && permissionNames == null) {
             for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
                 if (packageName != null && !packageName.equals(e.getKey())
                         && !packageName.equals(e.getValue())) {
@@ -4279,7 +4294,7 @@
                     printedSomething = true;
                 }
                 dumpPackageLPr(pw, "  ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
-                        users);
+                        users, packageName != null);
             }
         }
     }
@@ -4364,7 +4379,8 @@
                     if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
                         pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
                         dumpGidsLPr(pw, prefix + "  ", gids);
-                        dumpRuntimePermissionsLPr(pw, prefix + "  ", permissionNames, permissions);
+                        dumpRuntimePermissionsLPr(pw, prefix + "  ", permissionNames, permissions,
+                                packageName != null);
                     }
                 }
             } else {
@@ -4410,8 +4426,8 @@
     }
 
     void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
-            List<PermissionState> permissionStates) {
-        if (!permissionStates.isEmpty()) {
+            List<PermissionState> permissionStates, boolean dumpAll) {
+        if (!permissionStates.isEmpty() || dumpAll) {
             pw.print(prefix); pw.println("runtime permissions:");
             for (PermissionState permissionState : permissionStates) {
                 if (permissionNames != null
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7bd0635..a2307f9 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -651,7 +652,7 @@
      * when a thumbnail is specified with the activity options.
      */
     Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight,
-            int deviceWidth, int transit) {
+            int deviceWidth) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -659,7 +660,6 @@
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
 
         float scaleW = deviceWidth / thumbWidth;
-        float unscaledWidth = deviceWidth;
         float unscaledHeight = thumbHeight * scaleW;
         float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f;
         if (mNextAppTransitionScaleUp) {
@@ -716,7 +716,7 @@
      */
     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
             int appWidth, int appHeight, int orientation, int transit, Rect containingFrame,
-            Rect contentInsets) {
+            Rect contentInsets, @Nullable Rect surfaceInsets, boolean resizedWindow) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionStartWidth;
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -729,40 +729,45 @@
 
         switch (thumbTransitState) {
             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
-                // App window scaling up to become full screen
-                if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-                    // In portrait, we scale the width and clip to the top/left square
-                    scale = thumbWidth / appWidth;
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbHeight = (int) (thumbHeight / scale);
-                    mTmpFromClipRect.set(containingFrame);
-                    mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
-                    mTmpToClipRect.set(containingFrame);
+                if (resizedWindow) {
+                    a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+                            containingFrame, surfaceInsets);
                 } else {
-                    // In landscape, we scale the height and clip to the top/left square
-                    scale = thumbHeight / (appHeight - contentInsets.top);
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbWidth = (int) (thumbWidth / scale);
-                    mTmpFromClipRect.set(containingFrame);
-                    mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
-                    mTmpToClipRect.set(containingFrame);
+                    // App window scaling up to become full screen
+                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        // In portrait, we scale the width and clip to the top/left square
+                        scale = thumbWidth / appWidth;
+                        scaledTopDecor = (int) (scale * contentInsets.top);
+                        int unscaledThumbHeight = (int) (thumbHeight / scale);
+                        mTmpFromClipRect.set(containingFrame);
+                        mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
+                        mTmpToClipRect.set(containingFrame);
+                    } else {
+                        // In landscape, we scale the height and clip to the top/left square
+                        scale = thumbHeight / (appHeight - contentInsets.top);
+                        scaledTopDecor = (int) (scale * contentInsets.top);
+                        int unscaledThumbWidth = (int) (thumbWidth / scale);
+                        mTmpFromClipRect.set(containingFrame);
+                        mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
+                        mTmpToClipRect.set(containingFrame);
+                    }
+                    // exclude top screen decor (status bar) region from the source clip.
+                    mTmpFromClipRect.top = contentInsets.top;
+
+                    mNextAppTransitionInsets.set(contentInsets);
+
+                    Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
+                            computePivot(mNextAppTransitionStartX, scale),
+                            computePivot(mNextAppTransitionStartY, scale));
+                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+                    Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+
+                    AnimationSet set = new AnimationSet(true);
+                    set.addAnimation(clipAnim);
+                    set.addAnimation(scaleAnim);
+                    set.addAnimation(translateAnim);
+                    a = set;
                 }
-                // exclude top screen decor (status bar) region from the source clip.
-                mTmpFromClipRect.top = contentInsets.top;
-
-                mNextAppTransitionInsets.set(contentInsets);
-
-                Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
-                        computePivot(mNextAppTransitionStartX, scale),
-                        computePivot(mNextAppTransitionStartY, scale));
-                Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-                Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
-
-                AnimationSet set = new AnimationSet(true);
-                set.addAnimation(clipAnim);
-                set.addAnimation(scaleAnim);
-                set.addAnimation(translateAnim);
-                a = set;
                 break;
             }
             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -836,6 +841,31 @@
                 mTouchResponseInterpolator);
     }
 
+    private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+            Rect containingFrame, @Nullable Rect surfaceInsets) {
+        float width = containingFrame.width();
+        float height = containingFrame.height();
+        float scaleWidth = mNextAppTransitionStartWidth / width;
+        float scaleHeight = mNextAppTransitionStartHeight / height;
+        AnimationSet set = new AnimationSet(true);
+        int surfaceInsetsHorizontal = surfaceInsets == null
+                ? 0 : surfaceInsets.left + surfaceInsets.right;
+        int surfaceInsetsVertical = surfaceInsets == null
+                ? 0 : surfaceInsets.top + surfaceInsets.bottom;
+        // We want the scaling to happen from the center of the surface. In order to achieve that,
+        // we need to account for surface insets that will be used to enlarge the surface.
+        ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
+                (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
+        int fromX = mNextAppTransitionStartX + mNextAppTransitionStartWidth / 2
+                - (containingFrame.left + containingFrame.width() / 2);
+        int fromY = mNextAppTransitionStartY + mNextAppTransitionStartHeight / 2
+                - (containingFrame.top + containingFrame.height() / 2);
+        TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
+        set.addAnimation(scale);
+        set.addAnimation(translation);
+        return set;
+    }
+
     /**
      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
      * when a thumbnail is specified with the activity options.
@@ -881,7 +911,7 @@
      * leaving, and the activity that is entering.
      */
     Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
-                                                    int appHeight, int transit) {
+            int appHeight, int transit) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -954,7 +984,8 @@
 
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
             int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
-            Rect appFrame, boolean isVoiceInteraction) {
+            @Nullable Rect surfaceInsets, Rect appFrame, boolean isVoiceInteraction,
+            boolean resizedWindow) {
         Animation a;
         if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
                 || transit == TRANSIT_TASK_OPEN
@@ -1023,8 +1054,8 @@
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
             a = createAspectScaledThumbnailEnterExitAnimationLocked(
-                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
-                    transit, containingFrame, contentInsets);
+                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation, transit,
+                    containingFrame, contentInsets, surfaceInsets, resizedWindow);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9af5e14..5ec2137 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3448,8 +3448,8 @@
         }
     }
 
-    private boolean applyAnimationLocked(AppWindowToken atoken,
-            WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {
+    private boolean applyAnimationLocked(AppWindowToken atoken, WindowManager.LayoutParams lp,
+            int transit, boolean enter, boolean isVoiceInteraction) {
         // Only apply an animation if the display isn't frozen.  If it is
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
@@ -3466,24 +3466,36 @@
             Rect containingFrame = new Rect(0, 0, width, height);
             Rect contentInsets = new Rect();
             Rect appFrame = new Rect(0, 0, width, height);
-            if (win != null && win.isFullscreen(width, height)) {
-                // For fullscreen windows use the window frames and insets to set the thumbnail
-                // clip. For none-fullscreen windows we use the app display region so the clip
-                // isn't affected by the window insets.
+            Rect surfaceInsets = null;
+            final boolean fullscreen = win != null && win.isFullscreen(width, height);
+            // Dialog activities have windows with containing frame being very large, but not
+            // exactly fullscreen and much smaller mFrame. We use this distinction to identify
+            // dialog activities.
+            final boolean dialogWindow = win != null && !win.mContainingFrame.equals(win.mFrame);
+            if (win != null) {
                 containingFrame.set(win.mContainingFrame);
-                contentInsets.set(win.mContentInsets);
-                appFrame.set(win.mFrame);
+                surfaceInsets = win.getAttrs().surfaceInsets;
+                if (fullscreen) {
+                    // For fullscreen windows use the window frames and insets to set the thumbnail
+                    // clip. For none-fullscreen windows we use the app display region so the clip
+                    // isn't affected by the window insets.
+                    contentInsets.set(win.mContentInsets);
+                    appFrame.set(win.mFrame);
+                }
             }
 
+            final int containingWidth = containingFrame.width();
+            final int containingHeight = containingFrame.height();
             if (atoken.mLaunchTaskBehind) {
                 // Differentiate the two animations. This one which is briefly on the screen
                 // gets the !enter animation, and the other activity which remains on the
                 // screen gets the enter animation. Both appear in the mOpeningApps set.
                 enter = false;
             }
-            Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
-                    mCurConfiguration.orientation, containingFrame, contentInsets, appFrame,
-                    isVoiceInteraction);
+            final boolean resizedWindow = !fullscreen && !dialogWindow;
+            Animation a = mAppTransition.loadAnimation(lp, transit, enter, containingWidth,
+                    containingHeight, mCurConfiguration.orientation, containingFrame, contentInsets,
+                    surfaceInsets, appFrame, isVoiceInteraction, resizedWindow);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -3493,7 +3505,7 @@
                     }
                     Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
                 }
-                atoken.mAppAnimator.setAnimation(a, width, height,
+                atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
                         mAppTransition.canSkipFirstFrame());
             }
         } else {
@@ -9533,7 +9545,7 @@
                         // open/close animation (only on the way down)
                         anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(
                                 displayInfo.appWidth, displayInfo.appHeight,
-                                displayInfo.logicalWidth, transit);
+                                displayInfo.logicalWidth);
                         openingAppAnimator.thumbnailForceAboveLayer = Math.max(topOpeningLayer,
                                 topClosingLayer);
                         openingAppAnimator.deferThumbnailDestruction =
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 48f2a9d..5d33cbd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1090,7 +1090,6 @@
             if (selfTransformation) {
                 tmpMatrix.postConcat(mTransformation.getMatrix());
             }
-            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
             if (attachedTransformation != null) {
                 tmpMatrix.postConcat(attachedTransformation.getMatrix());
             }
@@ -1100,6 +1099,10 @@
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
+            // The translation that applies the position of the window needs to be applied at the
+            // end in case that other translations include scaling. Otherwise the scaling will
+            // affect this translation.
+            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
 
             //TODO (multidisplay): Magnification is supported only for the default display.
             if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 3d49308..5852b8e 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -97,7 +97,7 @@
      * @hide
      * */
     public static String getDefaultDialerApplication(Context context) {
-        return getDefaultDialerApplication(context, ActivityManager.getCurrentUser());
+        return getDefaultDialerApplication(context, context.getUserId());
     }
 
     /**
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 36d5d98..fe17c6e 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -2,6 +2,7 @@
         package="com.android.test.voiceinteraction">
 
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
 
     <application>
         <activity android:name="VoiceInteractionMain" android:label="Voice Interaction"