Merge "Fix rect convert from screen to surface coordinates with scaling"
diff --git a/api/current.txt b/api/current.txt
index 1dcd309..1d251ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2750,15 +2750,12 @@
     method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2796,7 +2793,6 @@
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2824,8 +2820,6 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(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 android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2842,8 +2836,6 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
-    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
-    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -33726,17 +33718,24 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
@@ -33745,6 +33744,8 @@
     method public void onTileRemoved();
     method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index adce480..d1421e5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -35896,17 +35896,24 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
@@ -35916,6 +35923,8 @@
     method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index 3fed632..91dcf34 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2750,15 +2750,12 @@
     method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2796,7 +2793,6 @@
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2824,8 +2820,6 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(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 android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2842,8 +2836,6 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
-    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
-    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -33740,17 +33732,24 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
@@ -33759,6 +33758,8 @@
     method public void onTileRemoved();
     method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a312e3f..690e674 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.Manifest;
+import android.annotation.SystemApi;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -762,7 +763,9 @@
      * @throws NetworkErrorException if the authenticator could not honor the
      *             request due to a network error
      * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+     * @hide
      */
+    @SystemApi
     public Bundle startAddAccountSession(
             final AccountAuthenticatorResponse response,
             final String accountType,
@@ -818,7 +821,9 @@
      * @throws NetworkErrorException if the authenticator could not honor the
      *             request due to a network error
      * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+     * @hide
      */
+    @SystemApi
     public Bundle startUpdateCredentialsSession(
             final AccountAuthenticatorResponse response,
             final Account account,
@@ -870,7 +875,9 @@
      *         </ul>
      * @throws NetworkErrorException
      * @see #startAddAccountSession and #startUpdateCredentialsSession
+     * @hide
      */
+    @SystemApi
     public Bundle finishSession(
             final AccountAuthenticatorResponse response,
             final String accountType,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index ada1ac2..2449ee5 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
+import android.annotation.SystemApi;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -244,14 +245,18 @@
      * Bundle key used for a {@link Bundle} in result from
      * {@link #startAddAccountSession} and friends which returns session data
      * for installing an account later.
+     * @hide
      */
+    @SystemApi
     public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
 
     /**
      * Bundle key used for the {@link String} account status token in result
      * from {@link #startAddAccountSession} and friends which returns
      * information about a particular account.
+     * @hide
      */
+    @SystemApi
     public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
 
     public static final String ACTION_AUTHENTICATOR_INTENT =
@@ -2667,7 +2672,9 @@
      *         trouble
      *         </ul>
      * @see #finishSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> startAddAccountSession(
             final String accountType,
             final String authTokenType,
@@ -2749,7 +2756,9 @@
      *         trouble
      *         </ul>
      * @see #finishSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
             final Account account,
             final String authTokenType,
@@ -2818,7 +2827,9 @@
      *         trouble
      *         </ul>
      * @see #startAddAccountSession and #startUpdateCredentialsSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> finishSession(
             final Bundle sessionBundle,
             final Activity activity,
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 9991d41..4bfc948 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -27,5 +27,9 @@
     void updateStatusIcon(in Tile tile, in Icon icon,
             String contentDescription);
     void onShowDialog(in Tile tile);
+    void onStartActivity(in Tile tile);
     void setTileMode(in ComponentName component, int mode);
+    boolean isLocked();
+    boolean isSecure();
+    void startUnlockAndRun(in Tile tile);
 }
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 4997f75..bfde870 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -29,4 +29,5 @@
     void onStartListening();
     void onStopListening();
     void onClick(IBinder wtoken);
+    void onUnlockComplete();
 }
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 6104913..85f1955 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -36,10 +36,37 @@
 
     private static final String TAG = "Tile";
 
+    /**
+     * This is the default state of any tile, until updated by the {@link TileService}.
+     * <p>
+     * An unavailable state indicates that for some reason this tile is not currently
+     * available to the user for some reason, and will have no click action.  The tile's
+     * icon will be tinted differently to reflect this state.
+     */
+    public static final int STATE_UNAVAILABLE = 0;
+
+    /**
+     * This represents a tile that is currently in a disabled state but is still interactable.
+     *
+     * A disabled state indicates that the tile is not currently active (e.g. wifi disconnected or
+     * bluetooth disabled), but is still interactable by the user to modify this state.  Tiles
+     * that have boolean states should use this to represent one of their states.  The tile's
+     * icon will be tinted differently to reflect this state, but still be distinct from unavailable.
+     */
+    public static final int STATE_INACTIVE = 1;
+
+    /**
+     * This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is on,
+     * cast is casting).
+     */
+    public static final int STATE_ACTIVE = 2;
+
     private ComponentName mComponentName;
     private Icon mIcon;
     private CharSequence mLabel;
     private CharSequence mContentDescription;
+    // Default to active until clients of the new API can update.
+    private int mState = STATE_ACTIVE;
 
     private IQSService mService;
 
@@ -79,6 +106,29 @@
     }
 
     /**
+     * The current state of the tile.
+     *
+     * @see #STATE_UNAVAILABLE
+     * @see #STATE_INACTIVE
+     * @see #STATE_ACTIVE
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Sets the current state for the tile.
+     *
+     * Does not take effect until {@link #updateTile()} is called.
+     *
+     * @param state One of {@link #STATE_UNAVAILABLE}, {@link #STATE_INACTIVE},
+     * {@link #STATE_ACTIVE}
+     */
+    public void setState(int state) {
+        mState = state;
+    }
+
+    /**
      * Gets the current icon for the tile.
      */
     public Icon getIcon() {
@@ -165,6 +215,7 @@
         } else {
             dest.writeByte((byte) 0);
         }
+        dest.writeInt(mState);
         TextUtils.writeToParcel(mLabel, dest, flags);
         TextUtils.writeToParcel(mContentDescription, dest, flags);
     }
@@ -180,6 +231,7 @@
         } else {
             mIcon = null;
         }
+        mState = source.readInt();
         mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
     }
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 6b12193..c02465b 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -118,6 +118,7 @@
     private Tile mTile;
     private IBinder mToken;
     private IQSService mService;
+    private Runnable mUnlockRunnable;
 
     @Override
     public void onDestroy() {
@@ -199,6 +200,8 @@
      * This will collapse the Quick Settings panel and show the dialog.
      *
      * @param dialog Dialog to show.
+     *
+     * @see #isLocked()
      */
     public final void showDialog(Dialog dialog) {
         dialog.getWindow().getAttributes().token = mToken;
@@ -211,6 +214,67 @@
     }
 
     /**
+     * Prompts the user to unlock the device before executing the Runnable.
+     * <p>
+     * The user will be prompted for their current security method if applicable
+     * and if successful, runnable will be executed.  The Runnable will not be
+     * executed if the user fails to unlock the device or cancels the operation.
+     */
+    public final void unlockAndRun(Runnable runnable) {
+        mUnlockRunnable = runnable;
+        try {
+            mService.startUnlockAndRun(mTile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Checks if the device is in a secure state.
+     *
+     * TileServices should detect when the device is secure and change their behavior
+     * accordingly.
+     *
+     * @return true if the device is secure.
+     */
+    public final boolean isSecure() {
+        try {
+            return mService.isSecure();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
+     * Checks if the lock screen is showing.
+     *
+     * When a device is locked, then {@link #showDialog} will not present a dialog, as it will
+     * be under the lock screen. If the behavior of the Tile is safe to do while locked,
+     * then the user should use {@link #startActivity} to launch an activity on top of the lock
+     * screen, otherwise the tile should use {@link #unlockAndRun(Runnable)} to give the
+     * user their security challenge.
+     *
+     * @return true if the device is locked.
+     */
+    public final boolean isLocked() {
+        try {
+            return mService.isLocked();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
+     * Start an activity while collapsing the panel.
+     */
+    public final void startActivityAndCollapse(Intent intent) {
+        startActivity(intent);
+        try {
+            mService.onStartActivity(mTile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Gets the {@link Tile} for this service.
      * <p/>
      * This tile may be used to get or set the current state for this
@@ -258,6 +322,11 @@
             public void onClick(IBinder wtoken) throws RemoteException {
                 mHandler.obtainMessage(H.MSG_TILE_CLICKED, wtoken).sendToTarget();
             }
+
+            @Override
+            public void onUnlockComplete() throws RemoteException{
+                mHandler.sendEmptyMessage(H.MSG_UNLOCK_COMPLETE);
+            }
         };
     }
 
@@ -269,6 +338,7 @@
         private static final int MSG_TILE_REMOVED = 5;
         private static final int MSG_TILE_CLICKED = 6;
         private static final int MSG_SET_SERVICE = 7;
+        private static final int MSG_UNLOCK_COMPLETE = 8;
 
         public H(Looper looper) {
             super(looper);
@@ -323,6 +393,11 @@
                     mToken = (IBinder) msg.obj;
                     TileService.this.onClick();
                     break;
+                case MSG_UNLOCK_COMPLETE:
+                    if (mUnlockRunnable != null) {
+                        mUnlockRunnable.run();
+                    }
+                    break;
             }
         }
     }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index e0dbe2f..1536c29 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -850,7 +850,7 @@
             normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
         }
 
-        final boolean expired = normalizedTime >= 1.0f;
+        final boolean expired = normalizedTime >= 1.0f || isCanceled();
         mMore = !expired;
 
         if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
@@ -875,7 +875,7 @@
         }
 
         if (expired) {
-            if (mRepeatCount == mRepeated) {
+            if (mRepeatCount == mRepeated || isCanceled()) {
                 if (!mEnded) {
                     mEnded = true;
                     guard.close();
@@ -905,6 +905,10 @@
         return mMore;
     }
 
+    private boolean isCanceled() {
+        return mStartTime == Long.MIN_VALUE;
+    }
+
     private void fireAnimationStart() {
         if (mListener != null) {
             if (mListenerHandler == null) mListener.onAnimationStart(this);
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 48d1d2b..ac8d578 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -59,7 +59,6 @@
  */
 public class ActionMenuPresenter extends BaseMenuPresenter
         implements ActionProvider.SubUiVisibilityListener {
-    private static final String TAG = "ActionMenuPresenter";
     private static final int ITEM_ANIMATION_DURATION = 150;
     private static final boolean ACTIONBAR_ANIMATIONS_ENABLED = false;
 
@@ -87,20 +86,16 @@
     private OpenOverflowRunnable mPostedOpenRunnable;
     private ActionMenuPopupCallback mPopupCallback;
 
-    private final boolean mShowCascadingMenus;
-
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
     // These collections are used to store pre- and post-layout information for menu items,
     // which is used to determine appropriate animations to run for changed items.
-    private SparseArray<MenuItemLayoutInfo> mPreLayoutItems =
-            new SparseArray<MenuItemLayoutInfo>();
-    private SparseArray<MenuItemLayoutInfo> mPostLayoutItems =
-            new SparseArray<MenuItemLayoutInfo>();
+    private SparseArray<MenuItemLayoutInfo> mPreLayoutItems = new SparseArray<>();
+    private SparseArray<MenuItemLayoutInfo> mPostLayoutItems = new SparseArray<>();
 
     // The list of currently running animations on menu items.
-    private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>();
+    private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<>();
     private ViewTreeObserver.OnPreDrawListener mItemAnimationPreDrawListener =
             new ViewTreeObserver.OnPreDrawListener() {
         @Override
@@ -130,9 +125,6 @@
     public ActionMenuPresenter(Context context) {
         super(context, com.android.internal.R.layout.action_menu_layout,
                 com.android.internal.R.layout.action_menu_item_layout);
-
-        mShowCascadingMenus = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableCascadingSubmenus);
     }
 
     @Override
@@ -845,8 +837,6 @@
     }
 
     private class OverflowMenuButton extends ImageButton implements ActionMenuView.ActionMenuChildView {
-        private final float[] mTempPts = new float[2];
-
         public OverflowMenuButton(Context context) {
             super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
 
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index 7ddeff9..b383e1c 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -53,12 +53,6 @@
     /** Whether this listener is currently forwarding touch events. */
     private boolean mForwarding;
 
-    /**
-     * Whether forwarding was initiated by a long-press. If so, we won't
-     * force the window to dismiss when the touch stream ends.
-     */
-    private boolean mWasLongPress;
-
     /** The id of the first pointer down in the current event stream. */
     private int mActivePointerId;
 
@@ -172,7 +166,6 @@
         switch (actionMasked) {
             case MotionEvent.ACTION_DOWN:
                 mActivePointerId = srcEvent.getPointerId(0);
-                mWasLongPress = false;
 
                 if (mDisallowIntercept == null) {
                     mDisallowIntercept = new DisallowIntercept();
@@ -243,7 +236,6 @@
         e.recycle();
 
         mForwarding = true;
-        mWasLongPress = true;
     }
 
     /**
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b95bc28..595adc2 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,18 +16,20 @@
 
 package android.widget;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -38,13 +40,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.WindowManager;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
-
-import java.util.Locale;
+import android.widget.AdapterView.OnItemSelectedListener;
 
 /**
  * A ListPopupWindow anchors itself to a host view and displays a
@@ -109,8 +105,6 @@
 
     private boolean mModal;
 
-    private int mLayoutDirection;
-
     PopupWindow mPopup;
 
     /**
@@ -174,7 +168,7 @@
      * 
      * @param context Context used for contained views.
      */
-    public ListPopupWindow(Context context) {
+    public ListPopupWindow(@NonNull Context context) {
         this(context, null, com.android.internal.R.attr.listPopupWindowStyle, 0);
     }
 
@@ -185,7 +179,7 @@
      * @param context Context used for contained views.
      * @param attrs Attributes from inflating parent views used to style the popup.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.listPopupWindowStyle, 0);
     }
 
@@ -197,7 +191,8 @@
      * @param attrs Attributes from inflating parent views used to style the popup.
      * @param defStyleAttr Default style attribute to use for popup content.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -210,7 +205,8 @@
      * @param defStyleAttr Style attribute to read for default styling of popup content.
      * @param defStyleRes Style resource ID to use for default styling of popup content.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         mContext = context;
         mHandler = new Handler(context.getMainLooper());
 
@@ -227,9 +223,6 @@
 
         mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
-        // Set the default layout direction to match the default locale one
-        final Locale locale = mContext.getResources().getConfiguration().locale;
-        mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
     }
 
     /**
@@ -238,7 +231,7 @@
      *
      * @param adapter The adapter to use to create this window's content.
      */
-    public void setAdapter(ListAdapter adapter) {
+    public void setAdapter(@Nullable ListAdapter adapter) {
         if (mObserver == null) {
             mObserver = new PopupDataSetObserver();
         } else if (mAdapter != null) {
@@ -371,7 +364,7 @@
     /**
      * @return The background drawable for the popup window.
      */
-    public Drawable getBackground() {
+    public @Nullable Drawable getBackground() {
         return mPopup.getBackground();
     }
 
@@ -380,7 +373,7 @@
      * 
      * @param d A drawable to set as the background.
      */
-    public void setBackgroundDrawable(Drawable d) {
+    public void setBackgroundDrawable(@Nullable Drawable d) {
         mPopup.setBackgroundDrawable(d);
     }
 
@@ -389,7 +382,7 @@
      * 
      * @param animationStyle Animation style to use.
      */
-    public void setAnimationStyle(int animationStyle) {
+    public void setAnimationStyle(@StyleRes int animationStyle) {
         mPopup.setAnimationStyle(animationStyle);
     }
 
@@ -399,7 +392,7 @@
      * 
      * @return Animation style that will be used.
      */
-    public int getAnimationStyle() {
+    public @StyleRes int getAnimationStyle() {
         return mPopup.getAnimationStyle();
     }
 
@@ -408,7 +401,7 @@
      * 
      * @return The popup's anchor view
      */
-    public View getAnchorView() {
+    public @Nullable View getAnchorView() {
         return mDropDownAnchorView;
     }
 
@@ -418,7 +411,7 @@
      * 
      * @param anchor The view to use as an anchor.
      */
-    public void setAnchorView(View anchor) {
+    public void setAnchorView(@Nullable View anchor) {
         mDropDownAnchorView = anchor;
     }
 
@@ -537,7 +530,7 @@
      * 
      * @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
      */
-    public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
+    public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener clickListener) {
         mItemClickListener = clickListener;
     }
 
@@ -546,9 +539,9 @@
      * 
      * @param selectedListener Listener to register.
      * 
-     * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
+     * @see ListView#setOnItemSelectedListener(OnItemSelectedListener)
      */
-    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) {
+    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener selectedListener) {
         mItemSelectedListener = selectedListener;
     }
 
@@ -558,7 +551,7 @@
      * 
      * @param prompt View to use as an informational prompt.
      */
-    public void setPromptView(View prompt) {
+    public void setPromptView(@Nullable View prompt) {
         boolean showing = isShowing();
         if (showing) {
             removePromptView();
@@ -686,7 +679,7 @@
      *
      * @param listener Listener that will be notified when the popup is dismissed.
      */
-    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+    public void setOnDismissListener(@Nullable PopupWindow.OnDismissListener listener) {
         mPopup.setOnDismissListener(listener);
     }
 
@@ -795,7 +788,7 @@
     /**
      * @return The currently selected item or null if the popup is not showing.
      */
-    public Object getSelectedItem() {
+    public @Nullable Object getSelectedItem() {
         if (!isShowing()) {
             return null;
         }
@@ -834,7 +827,7 @@
      * 
      * @see ListView#getSelectedView()
      */
-    public View getSelectedView() {
+    public @Nullable View getSelectedView() {
         if (!isShowing()) {
             return null;
         }
@@ -846,11 +839,11 @@
      * Only valid when {@link #isShowing()} == {@code true}.
      */
     @Override
-    public ListView getListView() {
+    public @Nullable ListView getListView() {
         return mDropDownList;
     }
 
-    DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
+    @NonNull DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
         return new DropDownListView(context, hijackFocus);
     }
 
@@ -874,7 +867,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
+    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
         // when the drop down is shown, we drive it directly
         if (isShowing()) {
             // the key events are forwarded to the list in the drop down view
@@ -969,7 +962,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
+    public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
             if (consumed && KeyEvent.isConfirmKey(keyCode)) {
@@ -993,7 +986,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+    public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
@@ -1159,7 +1152,6 @@
 
             mPopup.setContentView(dropDownView);
         } else {
-            dropDownView = (ViewGroup) mPopup.getContentView();
             final View view = mPromptView;
             if (view != null) {
                 LinearLayout.LayoutParams hintParams =
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index c2adc42..a67e43a 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.internal.view.menu;
 
 import android.content.Context;
@@ -7,7 +23,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -30,7 +45,7 @@
         MenuPresenter, OnKeyListener {
 
     private final Context mContext;
-    private final LayoutInflater mInflater;
+
     private final MenuBuilder mMenu;
     private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
@@ -79,8 +94,6 @@
     private Callback mPresenterCallback;
     private ViewTreeObserver mTreeObserver;
 
-    private ViewGroup mMeasureParent;
-
     /** Whether the popup has been dismissed. Once dismissed, it cannot be opened again. */
     private boolean mWasDismissed;
 
@@ -99,10 +112,10 @@
     public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
             int popupStyleRes, boolean overflowOnly) {
         mContext = Preconditions.checkNotNull(context);
-        mInflater = LayoutInflater.from(context);
         mMenu = menu;
         mOverflowOnly = overflowOnly;
-        mAdapter = new MenuAdapter(menu, mInflater, mOverflowOnly);
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly);
         mPopupStyleAttr = popupStyleAttr;
         mPopupStyleRes = popupStyleRes;
 
@@ -155,8 +168,7 @@
         mPopup.setDropDownGravity(mDropDownGravity);
 
         if (!mHasContentWidth) {
-            mContentWidth = measureIndividualMenuWidth(
-                    mAdapter, mMeasureParent, mContext, mPopupMaxWidth);
+            mContentWidth = measureIndividualMenuWidth(mAdapter, null, mContext, mPopupMaxWidth);
             mHasContentWidth = true;
         }
 
@@ -177,7 +189,9 @@
                             false);
             TextView titleView = (TextView) titleItemView.findViewById(
                     com.android.internal.R.id.title);
-            titleView.setText(mMenu.getHeaderTitle());
+            if (titleView != null) {
+                titleView.setText(mMenu.getHeaderTitle());
+            }
             titleItemView.setEnabled(false);
             listView.addHeaderView(titleItemView, null, false);
 
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 166656c..c4c655b 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -51,20 +51,25 @@
     // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
     for (int i = layers.entries().size() - 1; i >= 0; i--) {
         RenderNode* layerNode = layers.entries()[i].renderNode;
-        const Rect& layerDamage = layers.entries()[i].damage;
-        layerNode->computeOrdering();
+        // only schedule repaint if node still on layer - possible it may have been
+        // removed during a dropped frame, but layers may still remain scheduled so
+        // as not to lose info on what portion is damaged
+        if (CC_LIKELY(layerNode->getLayer() != nullptr)) {
+            const Rect& layerDamage = layers.entries()[i].damage;
+            layerNode->computeOrdering();
 
-        // map current light center into RenderNode's coordinate space
-        Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
-        layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
+            // map current light center into RenderNode's coordinate space
+            Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
+            layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
 
-        saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
-                layerDamage, lightCenter, nullptr, layerNode);
+            saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
+                    layerDamage, lightCenter, nullptr, layerNode);
 
-        if (layerNode->getDisplayList()) {
-            deferNodeOps(*layerNode);
+            if (layerNode->getDisplayList()) {
+                deferNodeOps(*layerNode);
+            }
+            restoreForLayer();
         }
-        restoreForLayer();
     }
 
     // Defer Fbo0
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 644f356..24d43df 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -512,11 +512,11 @@
 void CanvasContext::prepareAndDraw(RenderNode* node) {
     ATRACE_CALL();
 
+    nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
     UiFrameInfoBuilder(frameInfo)
         .addFlag(FrameInfoFlags::RTAnimation)
-        .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
-                mRenderThread.timeLord().latestVsync());
+        .setVsync(vsync, vsync);
 
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
@@ -578,7 +578,7 @@
     node->setPropertyFieldsDirty(RenderNode::GENERIC);
 
 #if HWUI_NEW_OPS
-    LOG_ALWAYS_FATAL("unsupported");
+    // TODO: support buildLayer
 #else
     mCanvas->markLayersAsBuildLayers();
     mCanvas->flushLayerUpdates();
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 905da13..0a56f92 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -147,4 +147,8 @@
 
     <color name="default_remote_input_background">@*android:color/notification_default_color</color>
     <color name="remote_input_hint">#4dffffff</color>
+
+    <color name="qs_tile_tint_unavailable">#40ffffff</color>
+    <color name="qs_tile_tint_inactive">#4dffffff</color>
+    <color name="qs_tile_tint_active">#ffffffff</color>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
index 95ff611..ac4f05f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
@@ -19,8 +19,9 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
-
+import android.graphics.drawable.Drawable;
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 
 public class BlankCustomTile extends QSTile<QSTile.State> {
@@ -72,7 +73,9 @@
         try {
             PackageManager pm = mContext.getPackageManager();
             ServiceInfo info = pm.getServiceInfo(mComponent, 0);
-            state.icon = new DrawableIcon(info.loadIcon(pm));
+            Drawable drawable = info.loadIcon(pm);
+            drawable.setTint(mContext.getColor(R.color.qs_tile_tint_active));
+            state.icon = new DrawableIcon(drawable);
             state.label = info.loadLabel(pm).toString();
             state.contentDescription = state.label;
         } catch (Exception e) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index eefff30..d398b64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -25,11 +25,14 @@
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
@@ -88,6 +91,7 @@
         mTile.setIcon(tile.getIcon());
         mTile.setLabel(tile.getLabel());
         mTile.setContentDescription(tile.getContentDescription());
+        mTile.setState(tile.getState());
     }
 
     public void onDialogShown() {
@@ -147,6 +151,9 @@
 
     @Override
     protected void handleClick() {
+        if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+            return;
+        }
         try {
             if (DEBUG) Log.d(TAG, "Adding token");
             mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
@@ -172,9 +179,15 @@
     @Override
     protected void handleUpdateState(State state, Object arg) {
         Drawable drawable = mTile.getIcon().loadDrawable(mContext);
-        drawable.setTint(mContext.getColor(android.R.color.white));
+        int color = mContext.getColor(getColor(mTile.getState()));
+        drawable.setTint(color);
         state.icon = new DrawableIcon(drawable);
         state.label = mTile.getLabel();
+        if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+            state.label = new SpannableStringBuilder().append(state.label,
+                    new ForegroundColorSpan(color),
+                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+        }
         if (mTile.getContentDescription() != null) {
             state.contentDescription = mTile.getContentDescription();
         } else {
@@ -187,6 +200,30 @@
         return MetricsLogger.QS_CUSTOM;
     }
 
+    public void startUnlockAndRun() {
+        mHost.startRunnableDismissingKeyguard(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mService.onUnlockComplete();
+                } catch (RemoteException e) {
+                }
+            }
+        });
+    }
+
+    private static int getColor(int state) {
+        switch (state) {
+            case Tile.STATE_UNAVAILABLE:
+                return R.color.qs_tile_tint_unavailable;
+            case Tile.STATE_INACTIVE:
+                return R.color.qs_tile_tint_inactive;
+            case Tile.STATE_ACTIVE:
+                return R.color.qs_tile_tint_active;
+        }
+        return 0;
+    }
+
     public static ComponentName getComponentFromSpec(String spec) {
         final String action = spec.substring(PREFIX.length(), spec.length() - 1);
         if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index d41cdde..3830ac5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -104,4 +104,14 @@
             return false;
         }
     }
+
+    public boolean onUnlockComplete() {
+        try {
+            mService.onUnlockComplete();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 8c5e87e..4977d80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -55,6 +55,7 @@
     private static final int MSG_ON_ADDED = 0;
     private static final int MSG_ON_REMOVED = 1;
     private static final int MSG_ON_CLICK = 2;
+    private static final int MSG_ON_UNLOCK_COMPLETE = 3;
 
     // Bind retry control.
     private static final int MAX_BIND_RETRIES = 5;
@@ -174,6 +175,15 @@
                 onClick(mClickBinder);
             }
         }
+        if (queue.contains(MSG_ON_UNLOCK_COMPLETE)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onUnlockComplete");
+            if (!mListening) {
+                Log.w(TAG, "Managed to get unlock on non-listening state...");
+                // Skipping unlock since lost click privileges.
+            } else {
+                onUnlockComplete();
+            }
+        }
         if (queue.contains(MSG_ON_REMOVED)) {
             if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
             if (mListening) {
@@ -348,6 +358,15 @@
     }
 
     @Override
+    public void onUnlockComplete() {
+        if (DEBUG) Log.d(TAG, "onUnlockComplete");
+        if (mWrapper == null || !mWrapper.onUnlockComplete()) {
+            queueMessage(MSG_ON_UNLOCK_COMPLETE);
+            handleDeath();
+        }
+    }
+
+    @Override
     public IBinder asBinder() {
         return mWrapper != null ? mWrapper.asBinder() : null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index a831c87..44d8776 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -36,6 +36,7 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -199,6 +200,16 @@
     }
 
     @Override
+    public void onStartActivity(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            mHost.collapsePanels();
+        }
+    }
+
+    @Override
     public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
         final ComponentName componentName = tile.getComponentName();
         String packageName = componentName.getPackageName();
@@ -228,6 +239,28 @@
         }
     }
 
+    @Override
+    public void startUnlockAndRun(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            customTile.startUnlockAndRun();
+        }
+    }
+
+    @Override
+    public boolean isLocked() {
+        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        return keyguardMonitor.isShowing();
+    }
+
+    @Override
+    public boolean isSecure() {
+        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
+    }
+
     private CustomTile getTileForComponent(ComponentName component) {
         synchronized (mServices) {
             return mTiles.get(component);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b65bf43..ad8e3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -440,6 +440,7 @@
                         + " dataState=" + state.getDataRegState());
             }
             mServiceState = state;
+            mDataNetType = state.getDataNetworkType();
             updateTelephony();
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index 6ebf488..f86c6a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -283,6 +283,11 @@
                 public void onClick(IBinder iBinder) throws RemoteException {
                     sendCallback("onClick");
                 }
+
+                @Override
+                public void onUnlockComplete() throws RemoteException {
+                    sendCallback("onUnlockComplete");
+                }
             };
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 13fc47d..b64fbea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -60,8 +60,8 @@
     protected NetworkControllerImpl mNetworkController;
     protected MobileSignalController mMobileSignalController;
     protected PhoneStateListener mPhoneStateListener;
-    private SignalStrength mSignalStrength;
-    private ServiceState mServiceState;
+    protected SignalStrength mSignalStrength;
+    protected ServiceState mServiceState;
     protected ConnectivityManager mMockCm;
     protected WifiManager mMockWm;
     protected SubscriptionManager mMockSm;
@@ -235,7 +235,7 @@
         mPhoneStateListener.onSignalStrengthsChanged(mSignalStrength);
     }
 
-    private void updateServiceState() {
+    protected void updateServiceState() {
         Log.d(TAG, "Sending Service State: " + mServiceState);
         mPhoneStateListener.onServiceStateChanged(mServiceState);
     }
@@ -246,6 +246,7 @@
     }
 
     public void updateDataConnectionState(int dataState, int dataNetType) {
+        when(mServiceState.getDataNetworkType()).thenReturn(dataNetType);
         mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 587e2b5..e4f858b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -115,6 +115,21 @@
                 TelephonyIcons.QS_DATA_4G);
     }
 
+    public void testDataChangeWithoutConnectionState() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+
+        verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_LTE);
+
+        Mockito.when(mServiceState.getDataNetworkType())
+                .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
+        updateServiceState();
+        verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_H);
+    }
+
     public void testDataActivity() {
         setupDefaultSignal();
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 11f9e2d..f345d7e 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2312,6 +2312,14 @@
         }
 
         final int uid = Binder.getCallingUid();
+        // Only allow system to start session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot stat add account session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
         final int userId = UserHandle.getUserId(uid);
         if (!canUserModifyAccounts(userId, uid)) {
             try {
@@ -2499,6 +2507,14 @@
         }
 
         final int uid = Binder.getCallingUid();
+        // Only allow system to finish session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot finish session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
         final int userId = UserHandle.getUserId(uid);
         if (!canUserModifyAccounts(userId, uid)) {
             sendErrorResponse(response,
@@ -2717,6 +2733,16 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
+
+        final int uid = Binder.getCallingUid();
+        // Only allow system to start session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot start update credentials session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 312e309..c112843 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4753,8 +4753,7 @@
     }
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.getLaunchBounds();
-        task.updateOverrideConfiguration(bounds);
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                 (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
@@ -4810,10 +4809,9 @@
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.getLaunchBounds();
-        task.updateOverrideConfiguration(bounds);
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
         mWindowManager.setAppTask(
-                r.appToken, task.taskId, mStackId, task.getLaunchBounds(), task.mOverrideConfig);
+                r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig);
         mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
         r.taskConfigOverride = task.mOverrideConfig;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c634e0e..022b60b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1673,7 +1673,7 @@
         if (task.mResizeable && options != null) {
             int stackId = options.getLaunchStackId();
             if (canUseActivityOptionsLaunchBounds(options, stackId)) {
-                Rect bounds = options.getLaunchBounds();
+                final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
                 task.updateOverrideConfiguration(bounds);
                 if (stackId == INVALID_STACK_ID) {
                     stackId = task.getLaunchStackId();
@@ -1841,6 +1841,7 @@
             // can have the right fullscreen state.
             bounds = null;
         }
+        bounds = TaskRecord.validateBounds(bounds);
 
         mTmpBounds.clear();
         mTmpConfigs.clear();
@@ -1857,8 +1858,8 @@
                     fitWithinBounds(tempRect2, bounds);
                     task.updateOverrideConfiguration(tempRect2);
                 } else {
-                    task.updateOverrideConfiguration(tempTaskBounds != null
-                            ? tempTaskBounds : bounds);
+                    task.updateOverrideConfiguration(
+                            tempTaskBounds != null ? tempTaskBounds : bounds);
                 }
             }
 
@@ -1973,6 +1974,7 @@
             // Nothing to do here...
             return true;
         }
+        bounds = TaskRecord.validateBounds(bounds);
 
         if (!mWindowManager.isValidTaskId(task.taskId)) {
             // Task doesn't exist in window manager yet (e.g. was restored from recents).
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index cfa4433..6fa8950 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1739,7 +1739,7 @@
         if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
             if (mSupervisor.canUseActivityOptionsLaunchBounds(
                     options, options.getLaunchStackId())) {
-                newBounds = options.getLaunchBounds();
+                newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
             }
         }
         return newBounds;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ae987e6..f7e30c0 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
@@ -1310,6 +1311,20 @@
         return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
+    Rect updateOverrideConfigurationFromLaunchBounds() {
+        final Rect bounds = validateBounds(getLaunchBounds());
+        updateOverrideConfiguration(bounds);
+        return bounds;
+    }
+
+    static Rect validateBounds(Rect bounds) {
+        if (bounds != null && bounds.isEmpty()) {
+            Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
+            return null;
+        }
+        return bounds;
+    }
+
     private void reportMultiWindowModeChange() {
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
@@ -1386,17 +1401,20 @@
 
     /** Returns the bounds that should be used to launch this task. */
     Rect getLaunchBounds() {
-        final int stackId = stack.mStackId;
-
         // If we're over lockscreen, forget about stack bounds and use fullscreen.
         if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
             return null;
         }
 
-        if (stack == null
-                || stackId == HOME_STACK_ID
-                || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
-            return (mResizeable && stack != null) ? stack.mBounds : null;
+        if (stack == null) {
+            return null;
+        }
+
+        final int stackId = stack.mStackId;
+        if (stackId == HOME_STACK_ID
+                || stackId == FULLSCREEN_WORKSPACE_STACK_ID
+                || (stackId == DOCKED_STACK_ID && !mResizeable)) {
+            return mResizeable ? stack.mBounds : null;
         } else if (!StackId.persistTaskBounds(stackId)) {
             return stack.mBounds;
         }
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 835ba17..a16fcd2 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -587,16 +587,16 @@
                     Slog.e(TAG, "Unable to create surface.", ex);
                     return false;
                 }
+
+                mSurfaceControl.setLayerStack(mDisplayLayerStack);
+                mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
+                mSurface = new Surface();
+                mSurface.copyFrom(mSurfaceControl);
+
+                mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+                        mDisplayId, mSurfaceControl);
+                mSurfaceLayout.onDisplayTransaction();
             }
-
-            mSurfaceControl.setLayerStack(mDisplayLayerStack);
-            mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
-            mSurface = new Surface();
-            mSurface.copyFrom(mSurfaceControl);
-
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
-                    mDisplayId, mSurfaceControl);
-            mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 433d887..b74b0f2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -673,6 +673,9 @@
                 slowChange = false;
             }
             mAppliedDimming = true;
+        } else if (mAppliedDimming) {
+            slowChange = false;
+            mAppliedDimming = false;
         }
 
         // If low power mode is enabled, cut the brightness level by half
@@ -685,6 +688,9 @@
                 slowChange = false;
             }
             mAppliedLowPower = true;
+        } else if (mAppliedLowPower) {
+            slowChange = false;
+            mAppliedLowPower = false;
         }
 
         // Animate the screen brightness when the screen is on or dozing.
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e75780f..27d6e03 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -18,7 +18,6 @@
 
 import android.app.ActivityManager.StackId;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Debug;
 import android.util.EventLog;
@@ -89,6 +88,7 @@
 
     /** Detach this stack from its display when animation completes. */
     boolean mDeferDetach;
+    private boolean mUpdateBoundsAfterRotation = false;
 
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
@@ -239,6 +239,7 @@
     }
 
     void updateDisplayInfo(Rect bounds) {
+        mUpdateBoundsAfterRotation = false;
         if (mDisplayContent != null) {
             for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
@@ -248,6 +249,7 @@
             } else if (mFullscreen) {
                 setBounds(null);
             } else {
+                mUpdateBoundsAfterRotation = true;
                 mTmpRect2.set(mBounds);
                 final int newRotation = mDisplayContent.getDisplayInfo().rotation;
                 if (mRotation == newRotation) {
@@ -265,6 +267,10 @@
      * yet.
      */
     void updateBoundsAfterRotation() {
+        if (!mUpdateBoundsAfterRotation) {
+            return;
+        }
+        mUpdateBoundsAfterRotation = false;
         final int newRotation = getDisplayInfo().rotation;
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (mStackId == DOCKED_STACK_ID) {