Merge "Do not allow Tasks to influence orientation under some conditions."
diff --git a/api/current.txt b/api/current.txt
index 6ecf213..33eb074 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -696,6 +696,8 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844129; // 0x1010561
+    field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -13769,6 +13771,26 @@
     field public static final android.graphics.Typeface SERIF;
   }
 
+  public static final class Typeface.Builder {
+    ctor public Typeface.Builder();
+    method public android.graphics.Typeface build();
+    method public static android.graphics.Typeface.Builder obtain();
+    method public void recycle();
+    method public void reset();
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setItalic(int);
+    method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.FileDescriptor);
+    method public android.graphics.Typeface.Builder setSourceFromFilePath(java.lang.String);
+    method public android.graphics.Typeface.Builder setTtcIndex(int);
+    method public android.graphics.Typeface.Builder setWeight(int);
+    field public static final int ITALIC = 1; // 0x1
+    field public static final int NORMAL = 0; // 0x0
+    field public static final int RESOLVE_BY_FONT_TABLE = -1; // 0xffffffff
+  }
+
   public static abstract interface Typeface.FontRequestCallback {
     method public abstract void onTypefaceRequestFailed(int);
     method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
@@ -41027,6 +41049,7 @@
 
   public static final class FontConfig.Axis implements android.os.Parcelable {
     ctor public FontConfig.Axis(int, float);
+    ctor public FontConfig.Axis(java.lang.String, float);
     method public int describeContents();
     method public float getStyleValue();
     method public int getTag();
@@ -44595,6 +44618,8 @@
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
     method public abstract android.graphics.drawable.Drawable getIcon();
+    method public default android.content.res.ColorStateList getIconTintList();
+    method public default android.graphics.PorterDuff.Mode getIconTintMode();
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -44622,6 +44647,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 2303433..60d7f2f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -809,6 +809,8 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844129; // 0x1010561
+    field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -3861,6 +3863,7 @@
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
+    method public void setDisablePreviewScreenshots(boolean);
     method public void setEnterSharedElementCallback(android.app.SharedElementCallback);
     method public void setExitSharedElementCallback(android.app.SharedElementCallback);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
@@ -14492,6 +14495,26 @@
     field public static final android.graphics.Typeface SERIF;
   }
 
+  public static final class Typeface.Builder {
+    ctor public Typeface.Builder();
+    method public android.graphics.Typeface build();
+    method public static android.graphics.Typeface.Builder obtain();
+    method public void recycle();
+    method public void reset();
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setItalic(int);
+    method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.FileDescriptor);
+    method public android.graphics.Typeface.Builder setSourceFromFilePath(java.lang.String);
+    method public android.graphics.Typeface.Builder setTtcIndex(int);
+    method public android.graphics.Typeface.Builder setWeight(int);
+    field public static final int ITALIC = 1; // 0x1
+    field public static final int NORMAL = 0; // 0x0
+    field public static final int RESOLVE_BY_FONT_TABLE = -1; // 0xffffffff
+  }
+
   public static abstract interface Typeface.FontRequestCallback {
     method public abstract void onTypefaceRequestFailed(int);
     method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
@@ -44479,6 +44502,7 @@
 
   public static final class FontConfig.Axis implements android.os.Parcelable {
     ctor public FontConfig.Axis(int, float);
+    ctor public FontConfig.Axis(java.lang.String, float);
     method public int describeContents();
     method public float getStyleValue();
     method public int getTag();
@@ -48048,6 +48072,8 @@
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
     method public abstract android.graphics.drawable.Drawable getIcon();
+    method public default android.content.res.ColorStateList getIconTintList();
+    method public default android.graphics.PorterDuff.Mode getIconTintMode();
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -48075,6 +48101,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 80e1002..39663f2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -696,6 +696,8 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844129; // 0x1010561
+    field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -13807,6 +13809,26 @@
     field public static final android.graphics.Typeface SERIF;
   }
 
+  public static final class Typeface.Builder {
+    ctor public Typeface.Builder();
+    method public android.graphics.Typeface build();
+    method public static android.graphics.Typeface.Builder obtain();
+    method public void recycle();
+    method public void reset();
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setItalic(int);
+    method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
+    method public android.graphics.Typeface.Builder setSourceFromFile(java.io.FileDescriptor);
+    method public android.graphics.Typeface.Builder setSourceFromFilePath(java.lang.String);
+    method public android.graphics.Typeface.Builder setTtcIndex(int);
+    method public android.graphics.Typeface.Builder setWeight(int);
+    field public static final int ITALIC = 1; // 0x1
+    field public static final int NORMAL = 0; // 0x0
+    field public static final int RESOLVE_BY_FONT_TABLE = -1; // 0xffffffff
+  }
+
   public static abstract interface Typeface.FontRequestCallback {
     method public abstract void onTypefaceRequestFailed(int);
     method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
@@ -41222,6 +41244,7 @@
 
   public static final class FontConfig.Axis implements android.os.Parcelable {
     ctor public FontConfig.Axis(int, float);
+    ctor public FontConfig.Axis(java.lang.String, float);
     method public int describeContents();
     method public float getStyleValue();
     method public int getTag();
@@ -44955,6 +44978,8 @@
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
     method public abstract android.graphics.drawable.Drawable getIcon();
+    method public default android.content.res.ColorStateList getIconTintList();
+    method public default android.graphics.PorterDuff.Mode getIconTintMode();
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -44982,6 +45007,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 07540f3..e149868 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7257,6 +7257,33 @@
         mAutoFillResetNeeded = true;
     }
 
+    /**
+     * If set to true, this indicates to the system that it should never take a
+     * screenshot of the activity to be used as a representation while it is not in a started state.
+     * <p>
+     * Note that the system may use the window background of the theme instead to represent
+     * the window when it is not running.
+     * <p>
+     * Also note that in comparison to {@link android.view.WindowManager.LayoutParams#FLAG_SECURE},
+     * this only affects the behavior when the activity's screenshot would be used as a
+     * representation when the activity is not in a started state, i.e. in Overview. The system may
+     * still take screenshots of the activity in other contexts; for example, when the user takes a
+     * screenshot of the entire screen, or when the active
+     * {@link android.service.voice.VoiceInteractionService} requests a screenshot via
+     * {@link android.service.voice.VoiceInteractionSession#SHOW_WITH_SCREENSHOT}.
+     *
+     * @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    public void setDisablePreviewScreenshots(boolean disable) {
+        try {
+            ActivityManager.getService().setDisablePreviewScreenshots(mToken, disable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to call setDisablePreviewScreenshots", e);
+        }
+    }
+
     class HostCallbacks extends FragmentHostCallback<Activity> {
         public HostCallbacks() {
             super(Activity.this /*activity*/);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index d940857..b08ca4f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -612,6 +612,11 @@
 
     void waitForNetworkStateUpdate(long procStateSeq);
 
+    /**
+     * See {@link android.app.Activity#setDisablePreviewScreenshots}
+     */
+    void setDisablePreviewScreenshots(IBinder token, boolean disable);
+
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids and arguments.
     // If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 9c15e00..70f9bdd 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -111,7 +111,6 @@
             mStyleValue = styleValue;
         }
 
-        /** @hide */
         public Axis(@NonNull String tagString, float styleValue) {
             if (!FontListParser.isValidTag(tagString)) {
                 throw new IllegalArgumentException("Invalid tag pattern: " + tagString);
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 6574bc0..a3cd0ba 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -20,8 +20,11 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -304,6 +307,8 @@
         private CharSequence itemTitle;
         private CharSequence itemTitleCondensed;
         private int itemIconResId;
+        private ColorStateList itemIconTintList = null;
+        private PorterDuff.Mode itemIconTintMode = null;
         private char itemAlphabeticShortcut;
         private int itemAlphabeticModifiers;
         private char itemNumericShortcut;
@@ -395,6 +400,22 @@
             itemTitle = a.getText(com.android.internal.R.styleable.MenuItem_title);
             itemTitleCondensed = a.getText(com.android.internal.R.styleable.MenuItem_titleCondensed);
             itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
+            if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
+                itemIconTintMode = Drawable.parseTintMode(a.getInt(
+                        com.android.internal.R.styleable.MenuItem_iconTintMode, -1),
+                        itemIconTintMode);
+            } else {
+                // Reset to null so that it's not carried over to the next item
+                itemIconTintMode = null;
+            }
+            if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTint)) {
+                itemIconTintList = a.getColorStateList(
+                        com.android.internal.R.styleable.MenuItem_iconTint);
+            } else {
+                // Reset to null so that it's not carried over to the next item
+                itemIconTintList = null;
+            }
+
             itemAlphabeticShortcut =
                     getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut));
             itemAlphabeticModifiers =
@@ -466,6 +487,14 @@
                 item.setShowAsAction(itemShowAsAction);
             }
 
+            if (itemIconTintMode != null) {
+                item.setIconTintMode(itemIconTintMode);
+            }
+
+            if (itemIconTintList != null) {
+                item.setIconTintList(itemIconTintList);
+            }
+
             if (itemListenerMethodName != null) {
                 if (mContext.isRestricted()) {
                     throw new IllegalStateException("The android:onClick attribute cannot "
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 6aaaedbe..b171ad0c 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -18,9 +18,12 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.LayoutRes;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View.OnCreateContextMenuListener;
@@ -221,11 +224,62 @@
     
     /**
      * Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
-     * loaded before).
+     * loaded before). Note that if you call {@link #setIconTintList(ColorStateList)} or
+     * {@link #setIconTintMode(PorterDuff.Mode)} on this item, and you use a custom menu presenter
+     * in your application, you have to apply the tinting explicitly on the {@link Drawable}
+     * returned by this method.
      * 
      * @return The icon as a Drawable.
      */
     public Drawable getIcon();
+
+    /**
+     * Applies a tint to this item's icon. Does not modify the
+     * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setIcon(Drawable)} or {@link #setIcon(int)} will
+     * automatically mutate the icon and apply the specified tint and
+     * tint mode using
+     * {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#MenuItem_iconTint
+     * @see #getIconTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public default MenuItem setIconTintList(@Nullable ColorStateList tint) { return this; }
+
+    /**
+     * @return the tint applied to this item's icon
+     * @attr ref android.R.styleable#MenuItem_iconTint
+     * @see #setIconTintList(ColorStateList)
+     */
+    @Nullable
+    public default ColorStateList getIconTintList() { return null; }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setIconTintList(ColorStateList)} to this item's icon. The default mode is
+     * {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#MenuItem_iconTintMode
+     * @see #setIconTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public default MenuItem setIconTintMode(@Nullable PorterDuff.Mode tintMode) { return this; }
+
+    /**
+     * Returns the blending mode used to apply the tint to this item's icon, if specified.
+     *
+     * @return the blending mode used to apply the tint to this item's icon
+     * @attr ref android.R.styleable#MenuItem_iconTintMode
+     * @see #setIconTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public default PorterDuff.Mode getIconTintMode() { return null; }
     
     /**
      * Change the Intent associated with this item.  By default there is no
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5269296..6c73b9b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7677,9 +7677,11 @@
                 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
                 ViewStructure child = structure.newChild(i);
-                // TODO(b/33197203): add CTS test to autofill virtual children based on
-                // Accessibility API.
-                child.setAutofillId(structure, i);
+                if (forAutofill) {
+                    // TODO(b/33197203): add CTS test to autofill virtual children based on
+                    // Accessibility API.
+                    child.setAutofillId(structure, i);
+                }
                 populateVirtualStructure(child, provider, cinfo, forAutofill);
                 cinfo.recycle();
             }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 9cbbc5a..21e39f6 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -106,6 +106,11 @@
      */
     void showTvPictureInPictureMenu();
 
+    /**
+     * Shows the global actions menu.
+     */
+    void showGlobalActionsMenu();
+
     void addQsTile(in ComponentName tile);
     void remQsTile(in ComponentName tile);
     void clickQsTile(in ComponentName tile);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 698e387..20db499 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -63,6 +63,15 @@
     void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
     void setSystemUiVisibility(int vis, int mask, String cause);
 
+    void onGlobalActionsShown();
+    void onGlobalActionsHidden();
+
+    /**
+     * These methods are needed for global actions control which the UI is shown in sysui.
+     */
+    void shutdown();
+    void reboot(boolean safeMode);
+
     void addTile(in ComponentName tile);
     void remTile(in ComponentName tile);
     void clickTile(in ComponentName tile);
diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/util/EmergencyAffordanceManager.java
similarity index 85%
rename from core/java/com/android/internal/policy/EmergencyAffordanceManager.java
rename to core/java/com/android/internal/util/EmergencyAffordanceManager.java
index eb75bd4..ba95bfc 100644
--- a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
+++ b/core/java/com/android/internal/util/EmergencyAffordanceManager.java
@@ -1,20 +1,18 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
  */
 
-package com.android.internal.policy;
+package com.android.internal.util;
 
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index ac226dd..b807a42 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -16,8 +16,11 @@
 
 package com.android.internal.view.menu;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -45,6 +48,10 @@
 
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
+    private ColorStateList mIconTintList = null;
+    private PorterDuff.Mode mIconTintMode = null;
+    private boolean mHasIconTint = false;
+    private boolean mHasIconTintMode = false;
 
     private Context mContext;
 
@@ -178,15 +185,65 @@
     public MenuItem setIcon(Drawable icon) {
         mIconDrawable = icon;
         mIconResId = NO_ICON;
+
+        applyIconTint();
         return this;
     }
 
     public MenuItem setIcon(int iconRes) {
         mIconResId = iconRes;
         mIconDrawable = mContext.getDrawable(iconRes);
+
+        applyIconTint();
         return this;
     }
 
+    @Override
+    public MenuItem setIconTintList(@Nullable ColorStateList iconTintList) {
+        mIconTintList = iconTintList;
+        mHasIconTint = true;
+
+        applyIconTint();
+
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public ColorStateList getIconTintList() {
+        return mIconTintList;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode iconTintMode) {
+        mIconTintMode = iconTintMode;
+        mHasIconTintMode = true;
+
+        applyIconTint();
+
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public PorterDuff.Mode getIconTintMode() {
+        return mIconTintMode;
+    }
+
+    private void applyIconTint() {
+        if (mIconDrawable != null && (mHasIconTint || mHasIconTintMode)) {
+            mIconDrawable = mIconDrawable.mutate();
+
+            if (mHasIconTint) {
+                mIconDrawable.setTintList(mIconTintList);
+            }
+
+            if (mHasIconTintMode) {
+                mIconDrawable.setTintMode(mIconTintMode);
+            }
+        }
+    }
+
     public MenuItem setIntent(Intent intent) {
         mIntent = intent;
         return this;
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 9310d14..101623c 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -18,9 +18,12 @@
 
 import com.android.internal.view.menu.MenuView.ItemView;
 
+import android.annotation.Nullable;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 import android.view.ActionProvider;
@@ -38,7 +41,7 @@
  */
 public final class MenuItemImpl implements MenuItem {
     private static final String TAG = "MenuItemImpl";
-    
+
     private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
             SHOW_AS_ACTION_IF_ROOM |
             SHOW_AS_ACTION_ALWAYS;
@@ -61,14 +64,20 @@
      * The icon's resource ID which is used to get the Drawable when it is
      * needed (if the Drawable isn't already obtained--only one of the two is
      * needed).
-     */ 
+     */
     private int mIconResId = NO_ICON;
-    
+
+    private ColorStateList mIconTintList = null;
+    private PorterDuff.Mode mIconTintMode = null;
+    private boolean mHasIconTint = false;
+    private boolean mHasIconTintMode = false;
+    private boolean mNeedToApplyIconTint = false;
+
     /** The menu to which this item belongs */
     private MenuBuilder mMenu;
     /** If this item should launch a sub menu, this is the sub menu to launch */
     private SubMenuBuilder mSubMenu;
-    
+
     private Runnable mItemCallback;
     private MenuItem.OnMenuItemClickListener mClickListener;
 
@@ -124,7 +133,7 @@
         String lang = menu.getContext().getResources().getConfiguration().locale.toString();
         if (sPrependShortcutLabel == null || !lang.equals(sLanguage)) {
             sLanguage = lang;
-            // This is instantiated from the UI thread, so no chance of sync issues 
+            // This is instantiated from the UI thread, so no chance of sync issues
             sPrependShortcutLabel = menu.getContext().getResources().getString(
                     com.android.internal.R.string.prepend_shortcut_label);
             sEnterShortcutLabel = menu.getContext().getResources().getString(
@@ -134,7 +143,7 @@
             sSpaceShortcutLabel = menu.getContext().getResources().getString(
                     com.android.internal.R.string.menu_space_shortcut_label);
         }
-        
+
         mMenu = menu;
         mId = id;
         mGroup = group;
@@ -143,10 +152,10 @@
         mTitle = title;
         mShowAsAction = showAsAction;
     }
-    
+
     /**
      * Invokes the item by calling various listeners or callbacks.
-     * 
+     *
      * @return true if the invocation was handled, false otherwise
      */
     public boolean invoke() {
@@ -179,7 +188,7 @@
 
         return false;
     }
-    
+
     public boolean isEnabled() {
         return (mFlags & ENABLED) != 0;
     }
@@ -192,10 +201,10 @@
         }
 
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
-    
+
     public int getGroupId() {
         return mGroup;
     }
@@ -208,11 +217,11 @@
     public int getOrder() {
         return mCategoryOrder;
     }
-    
+
     public int getOrdering() {
-        return mOrdering; 
+        return mOrdering;
     }
-    
+
     public Intent getIntent() {
         return mIntent;
     }
@@ -225,7 +234,7 @@
     Runnable getCallback() {
         return mItemCallback;
     }
-    
+
     public MenuItem setCallback(Runnable callback) {
         mItemCallback = callback;
         return this;
@@ -273,11 +282,11 @@
 
     public MenuItem setNumericShortcut(char numericChar) {
         if (mShortcutNumericChar == numericChar) return this;
-        
+
         mShortcutNumericChar = numericChar;
-        
+
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
 
@@ -297,9 +306,9 @@
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
-        
+
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
 
@@ -321,7 +330,7 @@
     char getShortcut() {
         return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
     }
-    
+
     /**
      * @return The label to show for the shortcut. This includes the chording
      *         key (for example 'Menu+a'). Also, any non-human readable
@@ -333,30 +342,30 @@
         if (shortcut == 0) {
             return "";
         }
-        
+
         StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
         switch (shortcut) {
-        
+
             case '\n':
                 sb.append(sEnterShortcutLabel);
                 break;
-            
+
             case '\b':
                 sb.append(sDeleteShortcutLabel);
                 break;
-            
+
             case ' ':
                 sb.append(sSpaceShortcutLabel);
                 break;
-            
+
             default:
                 sb.append(shortcut);
                 break;
         }
-        
+
         return sb.toString();
     }
-    
+
     /**
      * @return Whether this menu item should be showing shortcuts (depends on
      *         whether the menu should show shortcuts and whether this item has
@@ -366,7 +375,7 @@
         // Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
         return mMenu.isShortcutsVisible() && (getShortcut() != 0);
     }
-    
+
     public SubMenu getSubMenu() {
         return mSubMenu;
     }
@@ -377,10 +386,10 @@
 
     void setSubMenu(SubMenuBuilder subMenu) {
         mSubMenu = subMenu;
-        
+
         subMenu.setHeaderTitle(getTitle());
     }
-    
+
     @ViewDebug.CapturedViewProperty
     public CharSequence getTitle() {
         return mTitle;
@@ -388,7 +397,7 @@
 
     /**
      * Gets the title for a particular {@link ItemView}
-     * 
+     *
      * @param itemView The ItemView that is receiving the title
      * @return Either the title or condensed title based on what the ItemView
      *         prefers
@@ -403,68 +412,122 @@
         mTitle = title;
 
         mMenu.onItemsChanged(false);
-        
+
         if (mSubMenu != null) {
             mSubMenu.setHeaderTitle(title);
         }
-        
+
         return this;
     }
-    
+
     public MenuItem setTitle(int title) {
         return setTitle(mMenu.getContext().getString(title));
     }
-    
+
     public CharSequence getTitleCondensed() {
         return mTitleCondensed != null ? mTitleCondensed : mTitle;
     }
-    
+
     public MenuItem setTitleCondensed(CharSequence title) {
         mTitleCondensed = title;
 
-        // Could use getTitle() in the loop below, but just cache what it would do here 
+        // Could use getTitle() in the loop below, but just cache what it would do here
         if (title == null) {
             title = mTitle;
         }
-        
+
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
 
     public Drawable getIcon() {
         if (mIconDrawable != null) {
-            return mIconDrawable;
+            return applyIconTintIfNecessary(mIconDrawable);
         }
 
         if (mIconResId != NO_ICON) {
             Drawable icon =  mMenu.getContext().getDrawable(mIconResId);
             mIconResId = NO_ICON;
             mIconDrawable = icon;
-            return icon;
+            return applyIconTintIfNecessary(icon);
         }
-        
+
         return null;
     }
-    
+
     public MenuItem setIcon(Drawable icon) {
         mIconResId = NO_ICON;
         mIconDrawable = icon;
+        mNeedToApplyIconTint = true;
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
-    
+
     public MenuItem setIcon(int iconResId) {
         mIconDrawable = null;
         mIconResId = iconResId;
+        mNeedToApplyIconTint = true;
 
         // If we have a view, we need to push the Drawable to them
         mMenu.onItemsChanged(false);
-        
+
         return this;
     }
-    
+
+    @Override
+    public MenuItem setIconTintList(@Nullable ColorStateList iconTintList) {
+        mIconTintList = iconTintList;
+        mHasIconTint = true;
+        mNeedToApplyIconTint = true;
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public ColorStateList getIconTintList() {
+        return mIconTintList;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode iconTintMode) {
+        mIconTintMode = iconTintMode;
+        mHasIconTintMode = true;
+        mNeedToApplyIconTint = true;
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public PorterDuff.Mode getIconTintMode() {
+        return mIconTintMode;
+    }
+
+    private Drawable applyIconTintIfNecessary(Drawable icon) {
+        if (icon != null && mNeedToApplyIconTint && (mHasIconTint || mHasIconTintMode)) {
+            icon = icon.mutate();
+
+            if (mHasIconTint) {
+                icon.setTintList(mIconTintList);
+            }
+
+            if (mHasIconTintMode) {
+                icon.setTintMode(mIconTintMode);
+            }
+
+            mNeedToApplyIconTint = false;
+        }
+
+        return icon;
+    }
+
     public boolean isCheckable() {
         return (mFlags & CHECKABLE) == CHECKABLE;
     }
@@ -475,7 +538,7 @@
         if (oldFlags != mFlags) {
             mMenu.onItemsChanged(false);
         }
-        
+
         return this;
     }
 
@@ -486,7 +549,7 @@
     public boolean isExclusiveCheckable() {
         return (mFlags & EXCLUSIVE) != 0;
     }
-    
+
     public boolean isChecked() {
         return (mFlags & CHECKED) == CHECKED;
     }
@@ -499,7 +562,7 @@
         } else {
             setCheckedInt(checked);
         }
-        
+
         return this;
     }
 
@@ -510,7 +573,7 @@
             mMenu.onItemsChanged(false);
         }
     }
-    
+
     public boolean isVisible() {
         if (mActionProvider != null && mActionProvider.overridesItemVisibility()) {
             return (mFlags & HIDDEN) == 0 && mActionProvider.isVisible();
@@ -523,7 +586,7 @@
      * parent menu of a change in this item, so this should only be called from
      * methods that will eventually trigger this change.  If unsure, use {@link #setVisible(boolean)}
      * instead.
-     * 
+     *
      * @param shown Whether to show (true) or hide (false).
      * @return Whether the item's shown state was changed
      */
@@ -532,13 +595,13 @@
         mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
         return oldFlags != mFlags;
     }
-    
+
     public MenuItem setVisible(boolean shown) {
         // Try to set the shown state to the given state. If the shown state was changed
         // (i.e. the previous state isn't the same as given state), notify the parent menu that
         // the shown state has changed for this item
         if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
-        
+
         return this;
     }
 
@@ -546,7 +609,7 @@
         mClickListener = clickListener;
         return this;
     }
-    
+
     @Override
     public String toString() {
         return mTitle != null ? mTitle.toString() : null;
@@ -555,7 +618,7 @@
     void setMenuInfo(ContextMenuInfo menuInfo) {
         mMenuInfo = menuInfo;
     }
-    
+
     public ContextMenuInfo getMenuInfo() {
         return mMenuInfo;
     }
@@ -570,15 +633,15 @@
     public boolean shouldShowIcon() {
         return mMenu.getOptionalIconsVisible();
     }
-    
+
     public boolean isActionButton() {
         return (mFlags & IS_ACTION) == IS_ACTION;
     }
-    
+
     public boolean requestsActionButton() {
         return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
     }
-    
+
     public boolean requiresActionButton() {
         return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
     }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 95b2593..64e1620e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -210,10 +210,7 @@
     $(TOP)/system/media/camera/include \
     $(TOP)/system/netd/include \
     external/giflib \
-    external/pdfium/core/include/fpdfapi \
-    external/pdfium/fpdfsdk/include \
     external/pdfium/public \
-    external/pdfium \
     external/skia/include/private \
     external/skia/src/core \
     external/skia/src/effects \
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 6e7b6b8..1001c05 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -23,11 +23,6 @@
 #include "SkMatrix.h"
 #include "fpdfview.h"
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
-#include "fsdk_rendercontext.h"
-#pragma GCC diagnostic pop
-
 #include "core_jni_helpers.h"
 #include <vector>
 #include <utils/Log.h>
@@ -80,103 +75,10 @@
     HANDLE_PDFIUM_ERROR_STATE(env)
 }
 
-static void DropContext(void* data) {
-    delete (CRenderContext*) data;
-}
-
-static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, int destTop,
-        int destRight, int destBottom, SkMatrix* transform, int flags) {
-    // Note: this code ignores the currently unused RENDER_NO_NATIVETEXT,
-    // FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_FORCEHALFTONE, FPDF_GRAYSCALE,
-    // and FPDF_ANNOT flags. To add support for that refer to FPDF_RenderPage_Retail
-    // in fpdfview.cpp
-
-    CRenderContext* pContext = new CRenderContext;
-
-    CPDF_Page* pPage = (CPDF_Page*) page;
-    pPage->SetPrivateData((void*) 1, pContext, DropContext);
-
-    CFX_FxgeDevice* fxgeDevice = new CFX_FxgeDevice;
-    pContext->m_pDevice = fxgeDevice;
-
-    // Reverse the bytes (last argument TRUE) since the Android
-    // format is ARGB while the renderer uses BGRA internally.
-    fxgeDevice->Attach((CFX_DIBitmap*) bitmap, 0, TRUE);
-
-    CPDF_RenderOptions* renderOptions = pContext->m_pOptions;
-
-    if (!renderOptions) {
-        renderOptions = new CPDF_RenderOptions;
-        pContext->m_pOptions = renderOptions;
-    }
-
-    if (flags & FPDF_LCD_TEXT) {
-        renderOptions->m_Flags |= RENDER_CLEARTYPE;
-    } else {
-        renderOptions->m_Flags &= ~RENDER_CLEARTYPE;
-    }
-
-    const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING)
-            ? CPDF_OCContext::Print : CPDF_OCContext::View;
-
-    renderOptions->m_AddFlags = flags >> 8;
-    renderOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage);
-
-    fxgeDevice->SaveState();
-
-    FX_RECT clip;
-    clip.left = destLeft;
-    clip.right = destRight;
-    clip.top = destTop;
-    clip.bottom = destBottom;
-    fxgeDevice->SetClip_Rect(&clip);
-
-    CPDF_RenderContext* pageContext = new CPDF_RenderContext(pPage);
-    pContext->m_pContext = pageContext;
-
-    CFX_Matrix matrix;
-    if (!transform) {
-        pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft,
-                destBottom - destTop, 0);
-    } else {
-        // PDF's coordinate system origin is left-bottom while
-        // in graphics it is the top-left, so remap the origin.
-        SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1);
-        SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page));
-        SkMatrix m = SkMatrix::Concat(moveUp, reflectOnX);
-
-        // Concatenate transformation and origin transformation
-        m.setConcat(*transform, m);
-
-        SkScalar transformValues[6];
-        if (!m.asAffine(transformValues)) {
-            // Already checked for a return value of false in the caller, so this should never
-            // happen.
-            ALOGE("Error rendering page!");
-        }
-
-        matrix = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
-                  transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
-                  transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]};
-    }
-    pageContext->AppendObjectList(pPage, &matrix);
-
-    pContext->m_pRenderer = new CPDF_ProgressiveRenderer(pageContext, fxgeDevice, renderOptions);
-    pContext->m_pRenderer->Start(NULL);
-
-    fxgeDevice->RestoreState();
-
-    pPage->RemovePrivateData((void*) 1);
-
-    delete pContext;
-}
-
 static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
-        jobject jbitmap, jint destLeft, jint destTop, jint destRight, jint destBottom,
-        jlong matrixPtr, jint renderMode) {
-
+        jobject jbitmap, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
+        jlong transformPtr, jint renderMode) {
     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
-    SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
 
     SkBitmap skBitmap;
     GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap);
@@ -187,27 +89,49 @@
 
     FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
             FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
-
-    if (!bitmap) {
-        ALOGE("Erorr creating bitmap");
+    bool isExceptionPending = forwardPdfiumError(env);
+    if (isExceptionPending || bitmap == NULL) {
+        ALOGE("Error creating bitmap");
         return;
     }
 
-    int renderFlags = 0;
+    int renderFlags = FPDF_REVERSE_BYTE_ORDER;
     if (renderMode == RENDER_MODE_FOR_DISPLAY) {
         renderFlags |= FPDF_LCD_TEXT;
     } else if (renderMode == RENDER_MODE_FOR_PRINT) {
         renderFlags |= FPDF_PRINTING;
     }
 
-    if (skMatrix && !skMatrix->asAffine(NULL)) {
+    // PDF's coordinate system origin is left-bottom while in graphics it
+    // is the top-left. So, translate the PDF coordinates to ours.
+    SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1);
+    SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page));
+    SkMatrix coordinateChange = SkMatrix::Concat(moveUp, reflectOnX);
+
+    // Apply the transformation
+    SkMatrix matrix;
+    if (transformPtr == 0) {
+        matrix = coordinateChange;
+    } else {
+        matrix = SkMatrix::Concat(*reinterpret_cast<SkMatrix*>(transformPtr), coordinateChange);
+    }
+
+    SkScalar transformValues[6];
+    if (!matrix.asAffine(transformValues)) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                 "transform matrix has perspective. Only affine matrices are allowed.");
         return;
     }
 
-    renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
-            destBottom, skMatrix, renderFlags);
+    FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+                           transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+                           transformValues[SkMatrix::kATransX],
+                           transformValues[SkMatrix::kATransY]};
+
+    FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+    FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags);
+    HANDLE_PDFIUM_ERROR_STATE(env);
 
     skBitmap.notifyPixelsChanged();
 }
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e1068ea..3a1cf77 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7010,6 +7010,30 @@
              the title should be sufficient in describing this item. -->
         <attr name="icon" />
 
+        <!-- Tint to apply to the icon. -->
+        <attr name="iconTint" format="color" />
+
+        <!-- Blending mode used to apply the icon tint. -->
+        <attr name="iconTintMode">
+            <!-- The tint is drawn on top of the icon.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the icon. The icon’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the icon, but with the icon’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the icon with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and icon color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+
         <!-- The alphabetic shortcut key.  This is the shortcut when using a keyboard
              with alphabetic keys. -->
         <attr name="alphabeticShortcut" format="string" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index baad148..d6b5527 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2810,6 +2810,8 @@
         <public name="isFeatureSplit" />
         <public name="singleLineTitle" />
         <public name="fontProviderCerts" />
+        <public name="iconTint" />
+        <public name="iconTintMode" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
new file mode 100644
index 0000000..ed96bc1
--- /dev/null
+++ b/core/tests/coretests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Core Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksCoreTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksCoreTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.frameworks.coretests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 46a0d9b..a4b0916 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -25,4 +25,6 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_PACKAGE)
diff --git a/core/tests/utiltests/AndroidTest.xml b/core/tests/utiltests/AndroidTest.xml
new file mode 100644
index 0000000..9ebf568
--- /dev/null
+++ b/core/tests/utiltests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Utility Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksUtilTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksUtilTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.frameworks.utiltests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 1b25a62..6214ba6 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -142,6 +142,11 @@
                 isItalic);
     }
 
+    // TODO: Remove once internal user stop using private API.
+    private static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) {
+        return nAddFont(builderPtr, font, ttcIndex, -1, -1);
+    }
+
     private static native long nInitBuilder(String lang, int variant);
 
     @CriticalNative
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c74f65b..042bac6 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -490,7 +490,6 @@
      *
      * <p>Note that only one source can be specified for the single Typeface.</p>
      */
-    /** @hide TODO: Make this API public. */
     public static final class Builder {
         /**
          * Value for weight and italic.
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 99a0422..7b7a290 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -411,7 +411,18 @@
             final int contentBottom = (destClip != null) ? destClip.bottom
                     : destination.getHeight();
 
-            final long transformPtr = (transform != null) ? transform.native_instance : 0;
+            // If transform is not set, stretch page to whole clipped area
+            if (transform == null) {
+                int clipWidth = contentRight - contentLeft;
+                int clipHeight = contentBottom - contentTop;
+
+                transform = new Matrix();
+                transform.postScale((float)clipWidth / getWidth(),
+                        (float)clipHeight / getHeight());
+                transform.postTranslate(contentLeft, contentTop);
+            }
+
+            final long transformPtr = transform.native_instance;
 
             synchronized (sPdfiumLock) {
                 nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
@@ -463,7 +474,8 @@
     private static native int nativeGetPageCount(long documentPtr);
     private static native boolean nativeScaleForPrinting(long documentPtr);
     private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest,
-            int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
+            int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
+            int renderMode);
     private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
             Point outSize);
     private static native void nativeClosePage(long pagePtr);
diff --git a/packages/MtpDocumentsProvider/tests/AndroidTest.xml b/packages/MtpDocumentsProvider/tests/AndroidTest.xml
new file mode 100644
index 0000000..d0b4c6e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for MtpDocumentsProvider with the UI for output.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="MtpDocumentsProviderTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="MtpDocumentsProviderTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.mtp" />
+        <option name="runner" value="android.test.InstrumentationTestRunner" />
+    </test>
+</configuration>
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
new file mode 100644
index 0000000..7716992
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs PrintSpooler Out of Process Test Cases.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="PrintSpoolerOutOfProcessTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="PrintSpoolerOutOfProcessTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.printspooler.outofprocess.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/packages/SettingsLib/tests/integ/AndroidTest.xml b/packages/SettingsLib/tests/integ/AndroidTest.xml
new file mode 100644
index 0000000..8581acb
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for SettingsLib.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="SettingsLibTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="SettingsLibTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.settingslib" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/packages/Shell/tests/AndroidTest.xml b/packages/Shell/tests/AndroidTest.xml
new file mode 100644
index 0000000..ed9cb2b
--- /dev/null
+++ b/packages/Shell/tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for Shell.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="ShellTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="ShellTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.shell.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
new file mode 100644
index 0000000..bb21fb3
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(action = GlobalActions.ACTION, version = GlobalActions.VERSION)
+@DependsOn(target = GlobalActionsManager.class)
+public interface GlobalActions extends Plugin {
+
+    String ACTION = "com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS";
+    int VERSION = 1;
+
+    void showGlobalActions(GlobalActionsManager manager);
+
+    @ProvidesInterface(version = GlobalActionsManager.VERSION)
+    public interface GlobalActionsManager {
+        int VERSION = 1;
+
+        void onGlobalActionsShown();
+        void onGlobalActionsHidden();
+
+        void shutdown();
+        void reboot(boolean safeMode);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index e3ab05d..9435589 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -37,7 +37,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.policy.EmergencyAffordanceManager;
+import com.android.internal.util.EmergencyAffordanceManager;
 
 /**
  * This class implements a smart emergency button that updates itself based
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index be69867..51fa425 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -31,10 +31,12 @@
 import android.util.Log;
 
 import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyboard.KeyboardUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.media.RingtonePlayer;
 import com.android.systemui.pip.PipUI;
+import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
@@ -84,6 +86,7 @@
             VendorServices.class,
             GarbageMonitor.Service.class,
             LatencyTester.class,
+            GlobalActionsComponent.class,
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
new file mode 100644
index 0000000..f07027e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
+
+    private Extension<GlobalActions> mExtension;
+    private IStatusBarService mBarService;
+
+    @Override
+    public void start() {
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
+                .withPlugin(GlobalActions.class)
+                .withDefault(() -> new GlobalActionsImpl(mContext))
+                .build();
+        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
+    }
+
+    @Override
+    public void handleShowGlobalActionsMenu() {
+        mExtension.get().showGlobalActions(this);
+    }
+
+    @Override
+    public void onGlobalActionsShown() {
+        try {
+            mBarService.onGlobalActionsShown();
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public void onGlobalActionsHidden() {
+        try {
+            mBarService.onGlobalActionsHidden();
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public void shutdown() {
+        try {
+            mBarService.shutdown();
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public void reboot(boolean safeMode) {
+        try {
+            mBarService.reboot(safeMode);
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
new file mode 100644
index 0000000..206342e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -0,0 +1,1260 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import com.android.internal.R;
+import com.android.internal.app.AlertController;
+import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
+
+import android.app.ActivityManager;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper to show the global actions dialog.  Each item is an {@link Action} that
+ * may show depending on whether the keyguard is showing, and whether the device
+ * is provisioned.
+ */
+class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
+
+    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
+    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
+
+    private static final String TAG = "GlobalActionsDialog";
+
+    private static final boolean SHOW_SILENT_TOGGLE = true;
+
+    /* Valid settings for global actions keys.
+     * see config.xml config_globalActionList */
+    private static final String GLOBAL_ACTION_KEY_POWER = "power";
+    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+    private static final String GLOBAL_ACTION_KEY_USERS = "users";
+    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+    private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
+    private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+
+    private final Context mContext;
+    private final GlobalActionsManager mWindowManagerFuncs;
+    private final AudioManager mAudioManager;
+    private final IDreamManager mDreamManager;
+
+    private ArrayList<Action> mItems;
+    private ActionsDialog mDialog;
+
+    private Action mSilentModeAction;
+    private ToggleAction mAirplaneModeOn;
+
+    private MyAdapter mAdapter;
+
+    private boolean mKeyguardShowing = false;
+    private boolean mDeviceProvisioned = false;
+    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
+    private boolean mIsWaitingForEcmExit = false;
+    private boolean mHasTelephony;
+    private boolean mHasVibrator;
+    private final boolean mShowSilentToggle;
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
+
+    /**
+     * @param context everything needs a context :(
+     */
+    public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs) {
+        mContext = context;
+        mWindowManagerFuncs = windowManagerFuncs;
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.getService(DreamService.DREAM_SERVICE));
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        context.registerReceiver(mBroadcastReceiver, filter);
+
+        ConnectivityManager cm = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        // get notified of phone state changes
+        TelephonyManager telephonyManager =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
+                mAirplaneModeObserver);
+        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = vibrator != null && vibrator.hasVibrator();
+
+        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
+                R.bool.config_useFixedVolume);
+
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
+    }
+
+    /**
+     * Show the global actions dialog (creating if necessary)
+     * @param keyguardShowing True if keyguard is showing
+     */
+    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+        mKeyguardShowing = keyguardShowing;
+        mDeviceProvisioned = isDeviceProvisioned;
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+            // Show delayed, so that the dismiss of the previous dialog completes
+            mHandler.sendEmptyMessage(MESSAGE_SHOW);
+        } else {
+            handleShow();
+        }
+    }
+
+    private void awakenIfNecessary() {
+        if (mDreamManager != null) {
+            try {
+                if (mDreamManager.isDreaming()) {
+                    mDreamManager.awaken();
+                }
+            } catch (RemoteException e) {
+                // we tried
+            }
+        }
+    }
+
+    private void handleShow() {
+        awakenIfNecessary();
+        mDialog = createDialog();
+        prepareDialog();
+
+        // If we only have 1 item and it's a simple press action, just do this action.
+        if (mAdapter.getCount() == 1
+                && mAdapter.getItem(0) instanceof SinglePressAction
+                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
+            ((SinglePressAction) mAdapter.getItem(0)).onPress();
+        } else {
+            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+            attrs.setTitle("ActionsDialog");
+            mDialog.getWindow().setAttributes(attrs);
+            mDialog.show();
+            mWindowManagerFuncs.onGlobalActionsShown();
+            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+        }
+    }
+
+    /**
+     * Create the global actions dialog.
+     * @return A new dialog.
+     */
+    private ActionsDialog createDialog() {
+        // Simple toggle style if there's no vibrator, otherwise use a tri-state
+        if (!mHasVibrator) {
+            mSilentModeAction = new SilentModeToggleAction();
+        } else {
+            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
+        }
+        mAirplaneModeOn = new ToggleAction(
+                R.drawable.ic_lock_airplane_mode,
+                R.drawable.ic_lock_airplane_mode_off,
+                R.string.global_actions_toggle_airplane_mode,
+                R.string.global_actions_airplane_mode_on_status,
+                R.string.global_actions_airplane_mode_off_status) {
+
+            void onToggle(boolean on) {
+                if (mHasTelephony && Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                    mIsWaitingForEcmExit = true;
+                    // Launch ECM exit dialog
+                    Intent ecmDialogIntent =
+                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivity(ecmDialogIntent);
+                } else {
+                    changeAirplaneModeSystemSetting(on);
+                }
+            }
+
+            @Override
+            protected void changeStateFromPress(boolean buttonOn) {
+                if (!mHasTelephony) return;
+
+                // In ECM mode airplane state cannot be changed
+                if (!(Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                    mState = buttonOn ? State.TurningOn : State.TurningOff;
+                    mAirplaneState = mState;
+                }
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+        onAirplaneModeChanged();
+
+        mItems = new ArrayList<Action>();
+        String[] defaultActions = mContext.getResources().getStringArray(
+                R.array.config_globalActionsList);
+
+        ArraySet<String> addedKeys = new ArraySet<String>();
+        for (int i = 0; i < defaultActions.length; i++) {
+            String actionKey = defaultActions[i];
+            if (addedKeys.contains(actionKey)) {
+                // If we already have added this, don't add it again.
+                continue;
+            }
+            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+                mItems.add(new PowerAction());
+            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+                mItems.add(mAirplaneModeOn);
+            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
+                if (Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
+                    mItems.add(new BugReportAction());
+                }
+            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
+                if (mShowSilentToggle) {
+                    mItems.add(mSilentModeAction);
+                }
+            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
+                if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+                    addUsersToMenu(mItems);
+                }
+            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+                mItems.add(getSettingsAction());
+            } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
+                mItems.add(getLockdownAction());
+            } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
+                mItems.add(getVoiceAssistAction());
+            } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
+                mItems.add(getAssistAction());
+            } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
+                mItems.add(new RestartAction());
+            } else {
+                Log.e(TAG, "Invalid global action key " + actionKey);
+            }
+            // Add here so we don't add more than one.
+            addedKeys.add(actionKey);
+        }
+
+        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+            mItems.add(getEmergencyAction());
+        }
+
+        mAdapter = new MyAdapter();
+
+        AlertParams params = new AlertParams(mContext);
+        params.mAdapter = mAdapter;
+        params.mOnClickListener = this;
+        params.mForceInverseBackground = true;
+
+        ActionsDialog dialog = new ActionsDialog(mContext, params);
+        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
+
+        dialog.getListView().setItemsCanFocus(true);
+        dialog.getListView().setLongClickable(true);
+        dialog.getListView().setOnItemLongClickListener(
+                new AdapterView.OnItemLongClickListener() {
+                    @Override
+                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
+                            long id) {
+                        final Action action = mAdapter.getItem(position);
+                        if (action instanceof LongPressAction) {
+                            return ((LongPressAction) action).onLongPress();
+                        }
+                        return false;
+                    }
+        });
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+
+        dialog.setOnDismissListener(this);
+
+        return dialog;
+    }
+
+    private final class PowerAction extends SinglePressAction implements LongPressAction {
+        private PowerAction() {
+            super(R.drawable.ic_lock_power_off,
+                R.string.global_action_power_off);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+                mWindowManagerFuncs.reboot(true);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            // shutdown by making sure radio and power are handled accordingly.
+            mWindowManagerFuncs.shutdown();
+        }
+    }
+
+    private final class RestartAction extends SinglePressAction implements LongPressAction {
+        private RestartAction() {
+            super(R.drawable.ic_restart, R.string.global_action_restart);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+                mWindowManagerFuncs.reboot(true);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            mWindowManagerFuncs.reboot(false);
+        }
+    }
+
+
+    private class BugReportAction extends SinglePressAction implements LongPressAction {
+
+        public BugReportAction() {
+            super(R.drawable.ic_lock_bugreport, R.string.bugreport_title);
+        }
+
+        @Override
+        public void onPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
+                return;
+            }
+            // Add a little delay before executing, to give the
+            // dialog a chance to go away before it takes a
+            // screenshot.
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        // Take an "interactive" bugreport.
+                        MetricsLogger.action(mContext,
+                                MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
+                        ActivityManager.getService().requestBugReport(
+                                ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }, 500);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
+                return false;
+            }
+            try {
+                // Take a "full" bugreport.
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
+                ActivityManager.getService().requestBugReport(
+                        ActivityManager.BUGREPORT_OPTION_FULL);
+            } catch (RemoteException e) {
+            }
+            return false;
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        @Override
+        public String getStatus() {
+            return mContext.getString(
+                    R.string.bugreport_status,
+                    Build.VERSION.RELEASE,
+                    Build.ID);
+        }
+    }
+
+    private Action getSettingsAction() {
+        return new SinglePressAction(R.drawable.ic_settings,
+                R.string.global_action_settings) {
+
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Settings.ACTION_SETTINGS);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getEmergencyAction() {
+        return new SinglePressAction(R.drawable.emergency_icon,
+                R.string.global_action_emergency) {
+            @Override
+            public void onPress() {
+                mEmergencyAffordanceManager.performEmergencyCall();
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getAssistAction() {
+        return new SinglePressAction(R.drawable.ic_action_assist_focused,
+                R.string.global_action_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getVoiceAssistAction() {
+        return new SinglePressAction(R.drawable.ic_voice_search,
+                R.string.global_action_voice_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getLockdownAction() {
+        return new SinglePressAction(R.drawable.ic_lock_lock,
+                R.string.global_action_lockdown) {
+
+            @Override
+            public void onPress() {
+                new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+                try {
+                    WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error while trying to lock device.", e);
+                }
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+    }
+
+    private UserInfo getCurrentUser() {
+        try {
+            return ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    private boolean isCurrentUserOwner() {
+        UserInfo currentUser = getCurrentUser();
+        return currentUser == null || currentUser.isPrimary();
+    }
+
+    private void addUsersToMenu(ArrayList<Action> items) {
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (um.isUserSwitcherEnabled()) {
+            List<UserInfo> users = um.getUsers();
+            UserInfo currentUser = getCurrentUser();
+            for (final UserInfo user : users) {
+                if (user.supportsSwitchToByUser()) {
+                    boolean isCurrentUser = currentUser == null
+                            ? user.id == 0 : (currentUser.id == user.id);
+                    Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
+                            : null;
+                    SinglePressAction switchToUser = new SinglePressAction(
+                            R.drawable.ic_menu_cc, icon,
+                            (user.name != null ? user.name : "Primary")
+                            + (isCurrentUser ? " \u2714" : "")) {
+                        public void onPress() {
+                            try {
+                                ActivityManager.getService().switchUser(user.id);
+                            } catch (RemoteException re) {
+                                Log.e(TAG, "Couldn't switch user " + re);
+                            }
+                        }
+
+                        public boolean showDuringKeyguard() {
+                            return true;
+                        }
+
+                        public boolean showBeforeProvisioning() {
+                            return false;
+                        }
+                    };
+                    items.add(switchToUser);
+                }
+            }
+        }
+    }
+
+    private void prepareDialog() {
+        refreshSilentMode();
+        mAirplaneModeOn.updateState(mAirplaneState);
+        mAdapter.notifyDataSetChanged();
+        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        if (mShowSilentToggle) {
+            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mRingerModeReceiver, filter);
+        }
+    }
+
+    private void refreshSilentMode() {
+        if (!mHasVibrator) {
+            final boolean silentModeOn =
+                    mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
+            ((ToggleAction)mSilentModeAction).updateState(
+                    silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onDismiss(DialogInterface dialog) {
+        mWindowManagerFuncs.onGlobalActionsHidden();
+        if (mShowSilentToggle) {
+            try {
+                mContext.unregisterReceiver(mRingerModeReceiver);
+            } catch (IllegalArgumentException ie) {
+                // ignore this
+                Log.w(TAG, ie);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onClick(DialogInterface dialog, int which) {
+        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
+            dialog.dismiss();
+        }
+        mAdapter.getItem(which).onPress();
+    }
+
+    /**
+     * The adapter used for the list within the global actions dialog, taking
+     * into account whether the keyguard is showing via
+     * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing} and whether the device is provisioned
+     * via {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}.
+     */
+    private class MyAdapter extends BaseAdapter {
+
+        public int getCount() {
+            int count = 0;
+
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                count++;
+            }
+            return count;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItem(position).isEnabled();
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        public Action getItem(int position) {
+
+            int filteredPos = 0;
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                if (filteredPos == position) {
+                    return action;
+                }
+                filteredPos++;
+            }
+
+            throw new IllegalArgumentException("position " + position
+                    + " out of range of showable actions"
+                    + ", filtered count=" + getCount()
+                    + ", keyguardshowing=" + mKeyguardShowing
+                    + ", provisioned=" + mDeviceProvisioned);
+        }
+
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            Action action = getItem(position);
+            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
+        }
+    }
+
+    // note: the scheme below made more sense when we were planning on having
+    // 8 different things in the global actions dialog.  seems overkill with
+    // only 3 items now, but may as well keep this flexible approach so it will
+    // be easy should someone decide at the last minute to include something
+    // else, such as 'enable wifi', or 'enable bluetooth'
+
+    /**
+     * What each item in the global actions dialog must be able to support.
+     */
+    private interface Action {
+        /**
+         * @return Text that will be announced when dialog is created.  null
+         *     for none.
+         */
+        CharSequence getLabelForAccessibility(Context context);
+
+        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
+
+        void onPress();
+
+        /**
+         * @return whether this action should appear in the dialog when the keygaurd
+         *    is showing.
+         */
+        boolean showDuringKeyguard();
+
+        /**
+         * @return whether this action should appear in the dialog before the
+         *   device is provisioned.
+         */
+        boolean showBeforeProvisioning();
+
+        boolean isEnabled();
+    }
+
+    /**
+     * An action that also supports long press.
+     */
+    private interface LongPressAction extends Action {
+        boolean onLongPress();
+    }
+
+    /**
+     * A single press action maintains no state, just responds to a press
+     * and takes an action.
+     */
+    private static abstract class SinglePressAction implements Action {
+        private final int mIconResId;
+        private final Drawable mIcon;
+        private final int mMessageResId;
+        private final CharSequence mMessage;
+
+        protected SinglePressAction(int iconResId, int messageResId) {
+            mIconResId = iconResId;
+            mMessageResId = messageResId;
+            mMessage = null;
+            mIcon = null;
+        }
+
+        protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
+            mIconResId = iconResId;
+            mMessageResId = 0;
+            mMessage = message;
+            mIcon = icon;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        public String getStatus() {
+            return null;
+        }
+
+        abstract public void onPress();
+
+        public CharSequence getLabelForAccessibility(Context context) {
+            if (mMessage != null) {
+                return mMessage;
+            } else {
+                return context.getString(mMessageResId);
+            }
+        }
+
+        public View create(
+                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final String status = getStatus();
+            if (!TextUtils.isEmpty(status)) {
+                statusView.setText(status);
+            } else {
+                statusView.setVisibility(View.GONE);
+            }
+            if (mIcon != null) {
+                icon.setImageDrawable(mIcon);
+                icon.setScaleType(ScaleType.CENTER_CROP);
+            } else if (mIconResId != 0) {
+                icon.setImageDrawable(context.getDrawable(mIconResId));
+            }
+            if (mMessage != null) {
+                messageView.setText(mMessage);
+            } else {
+                messageView.setText(mMessageResId);
+            }
+
+            return v;
+        }
+    }
+
+    /**
+     * A toggle action knows whether it is on or off, and displays an icon
+     * and status message accordingly.
+     */
+    private static abstract class ToggleAction implements Action {
+
+        enum State {
+            Off(false),
+            TurningOn(true),
+            TurningOff(true),
+            On(false);
+
+            private final boolean inTransition;
+
+            State(boolean intermediate) {
+                inTransition = intermediate;
+            }
+
+            public boolean inTransition() {
+                return inTransition;
+            }
+        }
+
+        protected State mState = State.Off;
+
+        // prefs
+        protected int mEnabledIconResId;
+        protected int mDisabledIconResid;
+        protected int mMessageResId;
+        protected int mEnabledStatusMessageResId;
+        protected int mDisabledStatusMessageResId;
+
+        /**
+         * @param enabledIconResId The icon for when this action is on.
+         * @param disabledIconResid The icon for when this action is off.
+         * @param message The general information message, e.g 'Silent Mode'
+         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
+         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
+         */
+        public ToggleAction(int enabledIconResId,
+                int disabledIconResid,
+                int message,
+                int enabledStatusMessageResId,
+                int disabledStatusMessageResId) {
+            mEnabledIconResId = enabledIconResId;
+            mDisabledIconResid = disabledIconResid;
+            mMessageResId = message;
+            mEnabledStatusMessageResId = enabledStatusMessageResId;
+            mDisabledStatusMessageResId = disabledStatusMessageResId;
+        }
+
+        /**
+         * Override to make changes to resource IDs just before creating the
+         * View.
+         */
+        void willCreate() {
+
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return context.getString(mMessageResId);
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            willCreate();
+
+            View v = inflater.inflate(R
+                            .layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final boolean enabled = isEnabled();
+
+            if (messageView != null) {
+                messageView.setText(mMessageResId);
+                messageView.setEnabled(enabled);
+            }
+
+            boolean on = ((mState == State.On) || (mState == State.TurningOn));
+            if (icon != null) {
+                icon.setImageDrawable(context.getDrawable(
+                        (on ? mEnabledIconResId : mDisabledIconResid)));
+                icon.setEnabled(enabled);
+            }
+
+            if (statusView != null) {
+                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+                statusView.setVisibility(View.VISIBLE);
+                statusView.setEnabled(enabled);
+            }
+            v.setEnabled(enabled);
+
+            return v;
+        }
+
+        public final void onPress() {
+            if (mState.inTransition()) {
+                Log.w(TAG, "shouldn't be able to toggle when in transition");
+                return;
+            }
+
+            final boolean nowOn = !(mState == State.On);
+            onToggle(nowOn);
+            changeStateFromPress(nowOn);
+        }
+
+        public boolean isEnabled() {
+            return !mState.inTransition();
+        }
+
+        /**
+         * Implementations may override this if their state can be in on of the intermediate
+         * states until some notification is received (e.g airplane mode is 'turning off' until
+         * we know the wireless connections are back online
+         * @param buttonOn Whether the button was turned on or off
+         */
+        protected void changeStateFromPress(boolean buttonOn) {
+            mState = buttonOn ? State.On : State.Off;
+        }
+
+        abstract void onToggle(boolean on);
+
+        public void updateState(State state) {
+            mState = state;
+        }
+    }
+
+    private class SilentModeToggleAction extends ToggleAction {
+        public SilentModeToggleAction() {
+            super(R.drawable.ic_audio_vol_mute,
+                    R.drawable.ic_audio_vol,
+                    R.string.global_action_toggle_silent_mode,
+                    R.string.global_action_silent_mode_on_status,
+                    R.string.global_action_silent_mode_off_status);
+        }
+
+        void onToggle(boolean on) {
+            if (on) {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+            } else {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+            }
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+    }
+
+    private static class SilentModeTriStateAction implements Action, View.OnClickListener {
+
+        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+
+        private final AudioManager mAudioManager;
+        private final Handler mHandler;
+        private final Context mContext;
+
+        SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
+            mAudioManager = audioManager;
+            mHandler = handler;
+            mContext = context;
+        }
+
+        private int ringerModeToIndex(int ringerMode) {
+            // They just happen to coincide
+            return ringerMode;
+        }
+
+        private int indexToRingerMode(int index) {
+            // They just happen to coincide
+            return index;
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return null;
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
+
+            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
+            for (int i = 0; i < 3; i++) {
+                View itemView = v.findViewById(ITEM_IDS[i]);
+                itemView.setSelected(selectedIndex == i);
+                // Set up click handler
+                itemView.setTag(i);
+                itemView.setOnClickListener(this);
+            }
+            return v;
+        }
+
+        public void onPress() {
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        void willCreate() {
+        }
+
+        public void onClick(View v) {
+            if (!(v.getTag() instanceof Integer)) return;
+
+            int index = (Integer) v.getTag();
+            mAudioManager.setRingerMode(indexToRingerMode(index));
+            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+        }
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
+                if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
+                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
+                }
+            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+                // Airplane mode can be changed after ECM exits if airplane toggle button
+                // is pressed during ECM mode
+                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
+                        mIsWaitingForEcmExit) {
+                    mIsWaitingForEcmExit = false;
+                    changeAirplaneModeSystemSetting(true);
+                }
+            }
+        }
+    };
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            if (!mHasTelephony) return;
+            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
+            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
+            mAirplaneModeOn.updateState(mAirplaneState);
+            mAdapter.notifyDataSetChanged();
+        }
+    };
+
+    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
+            }
+        }
+    };
+
+    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            onAirplaneModeChanged();
+        }
+    };
+
+    private static final int MESSAGE_DISMISS = 0;
+    private static final int MESSAGE_REFRESH = 1;
+    private static final int MESSAGE_SHOW = 2;
+    private static final int DIALOG_DISMISS_DELAY = 300; // ms
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MESSAGE_DISMISS:
+                if (mDialog != null) {
+                    mDialog.dismiss();
+                    mDialog = null;
+                }
+                break;
+            case MESSAGE_REFRESH:
+                refreshSilentMode();
+                mAdapter.notifyDataSetChanged();
+                break;
+            case MESSAGE_SHOW:
+                handleShow();
+                break;
+            }
+        }
+    };
+
+    private void onAirplaneModeChanged() {
+        // Let the service state callbacks handle the state.
+        if (mHasTelephony) return;
+
+        boolean airplaneModeOn = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                0) == 1;
+        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
+        mAirplaneModeOn.updateState(mAirplaneState);
+    }
+
+    /**
+     * Change the airplane mode system setting
+     */
+    private void changeAirplaneModeSystemSetting(boolean on) {
+        Settings.Global.putInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                on ? 1 : 0);
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.putExtra("state", on);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        if (!mHasTelephony) {
+            mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
+        }
+    }
+
+    private static final class ActionsDialog extends Dialog implements DialogInterface {
+        private final Context mContext;
+        private final AlertController mAlert;
+        private final MyAdapter mAdapter;
+
+        public ActionsDialog(Context context, AlertParams params) {
+            super(context, getDialogTheme(context));
+            mContext = getContext();
+            mAlert = AlertController.create(mContext, this, getWindow());
+            mAdapter = (MyAdapter) params.mAdapter;
+            params.apply(mAlert);
+        }
+
+        private static int getDialogTheme(Context context) {
+            TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(R.attr.alertDialogTheme,
+                    outValue, true);
+            return outValue.resourceId;
+        }
+
+        @Override
+        protected void onStart() {
+            super.setCanceledOnTouchOutside(true);
+            super.onStart();
+        }
+
+        public ListView getListView() {
+            return mAlert.getListView();
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mAlert.installContent();
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                for (int i = 0; i < mAdapter.getCount(); ++i) {
+                    CharSequence label =
+                            mAdapter.getItem(i).getLabelForAccessibility(getContext());
+                    if (label != null) {
+                        event.getText().add(label);
+                    }
+                }
+            }
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyDown(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyUp(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyUp(keyCode, event);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
new file mode 100644
index 0000000..c1e51b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+import android.content.Context;
+import android.support.v7.view.ContextThemeWrapper;
+
+public class GlobalActionsImpl implements GlobalActions {
+
+    private final Context mContext;
+    private final KeyguardMonitor mKeyguardMonitor;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+    private GlobalActionsDialog mGlobalActions;
+
+    public GlobalActionsImpl(Context context) {
+        mContext = context;
+        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+    }
+
+    @Override
+    public void showGlobalActions(GlobalActionsManager manager) {
+        if (mGlobalActions == null) {
+            final ContextThemeWrapper context = new ContextThemeWrapper(mContext,
+                    android.R.style.Theme_Material_Light);
+            mGlobalActions = new GlobalActionsDialog(context, manager);
+        }
+        mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
+                mDeviceProvisionedController.isDeviceProvisioned());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 09b7bec..73bf454 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -78,6 +78,7 @@
     private static final int MSG_APP_TRANSITION_FINISHED       = 31 << MSG_SHIFT;
     private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS    = 32 << MSG_SHIFT;
     private static final int MSG_HANDLE_SYSNAV_KEY             = 33 << MSG_SHIFT;
+    private static final int MSG_SHOW_GLOBAL_ACTIONS           = 34 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -134,6 +135,7 @@
         default void clickTile(ComponentName tile) { }
 
         default void handleSystemNavigationKey(int arg1) { }
+        default void handleShowGlobalActionsMenu() { }
     }
 
     @VisibleForTesting
@@ -414,6 +416,14 @@
         }
     }
 
+    @Override
+    public void showGlobalActionsMenu() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
+            mHandler.obtainMessage(MSG_SHOW_GLOBAL_ACTIONS).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -590,6 +600,11 @@
                         mCallbacks.get(i).handleSystemNavigationKey(msg.arg1);
                     }
                     break;
+                case MSG_SHOW_GLOBAL_ACTIONS:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).handleShowGlobalActionsMenu();
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/tests/AndroidTest.xml b/packages/SystemUI/tests/AndroidTest.xml
new file mode 100644
index 0000000..ee78bcd
--- /dev/null
+++ b/packages/SystemUI/tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for SystemUI.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="SystemUITests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="SystemUITests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.systemui.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e0b7b47..d13cf77 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import static android.view.autofill.AutofillManager.FLAG_VIEW_EXITED;
 import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
 import static android.view.autofill.AutofillManager.FLAG_VALUE_CHANGED;
+import static android.view.autofill.AutofillManager.FLAG_MANUAL_REQUEST;
 
 import static com.android.server.autofill.Helper.DEBUG;
 import static com.android.server.autofill.Helper.VERBOSE;
@@ -1128,6 +1129,13 @@
                 return;
             }
 
+            if ((mFlags & FLAG_MANUAL_REQUEST) != 0 && response.getDatasets() != null
+                    && response.getDatasets().size() == 1) {
+                Slog.d(TAG, "autofilling manual request directly");
+                autoFill(response.getDatasets().get(0));
+                return;
+            }
+
             mCurrentViewState.setResponse(mCurrentResponse);
         }
 
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 2067620..c0d1107 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -957,7 +957,9 @@
                     // Unlock managed profile with unified lock
                     if (pi.isManagedProfile()
                             && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
-                            && mStorage.hasChildProfileLock(pi.id)) {
+                            && mStorage.hasChildProfileLock(pi.id)
+                            && mUserManager.isUserRunning(pi.id)
+                            && !mUserManager.isUserUnlocked(pi.id)) {
                         unlockChildProfile(pi.id);
                     }
                 }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1a7f016..490e63d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4891,7 +4891,6 @@
 
     private void installNotification(int notificationId, final Notification notification,
             String packageName, int userId) {
-        SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
         final long token = clearCallingIdentity();
         try {
             INotificationManager notificationManager = mInjector.getNotificationManager();
@@ -5678,6 +5677,7 @@
             synchronized (mUsers) {
                 userAccounts = mUsers.get(userId);
             }
+            SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
             doNotification(userAccounts, account, null, intent, packageName, userId);
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 05a59d3..2be5e77 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -128,7 +128,6 @@
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
 import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
 import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -149,8 +148,6 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
-import static java.lang.Integer.MAX_VALUE;
-
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.NonNull;
@@ -10851,6 +10848,25 @@
         }
     }
 
+    @Override
+    public void setDisablePreviewScreenshots(IBinder token, boolean disable)
+            throws RemoteException {
+        synchronized (this) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                Slog.w(TAG, "setDisablePreviewScreenshots: Unable to find activity for token="
+                        + token);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                r.setDisablePreviewScreenshots(disable);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
     // =========================================================
     // CONTENT PROVIDERS
     // =========================================================
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index b9bb106..6cea483 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1973,6 +1973,10 @@
                 task.taskId, requestedOrientation);
     }
 
+    void setDisablePreviewScreenshots(boolean disable) {
+        mWindowContainerController.setDisablePreviewScreenshots(disable);
+    }
+
     /**
      * Set the last reported global configuration to the client. Should be called whenever a new
      * global configuration is sent to the client for this activity.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fa73b6b..7e10a09 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3109,7 +3109,8 @@
                         + " - notification=" + notification);
                 return;
             }
-            throw new IllegalArgumentException("No Channel found for notification=" + notification);
+            throw new IllegalArgumentException("No Channel found for channelId=" + channelId
+                    + ", notification=" + notification);
         }
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index a42a70e..73afaa0 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -684,11 +684,11 @@
         NotificationChannel channel = r.channels.get(channelId);
         if (channel != null) {
             channel.setDeleted(true);
+            LogMaker lm = getChannelLog(channel, pkg);
+            lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+            MetricsLogger.action(lm);
+            updateConfig();
         }
-        LogMaker lm = getChannelLog(channel, pkg);
-        lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
-        MetricsLogger.action(lm);
-        updateConfig();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 335a230..17e5e9f 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -1,1257 +1,94 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
  */
 
 package com.android.server.policy;
 
-import com.android.internal.app.AlertController;
-import com.android.internal.app.AlertController.AlertParams;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.policy.EmergencyAffordanceManager;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
 
-import android.app.ActivityManager;
-import android.app.Dialog;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.os.Build;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
+import android.util.Slog;
 import android.view.WindowManagerPolicy.WindowManagerFuncs;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.ListView;
-import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Helper to show the global actions dialog.  Each item is an {@link Action} that
- * may show depending on whether the keyguard is showing, and whether the device
- * is provisioned.
- */
-class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
+class GlobalActions implements GlobalActionsListener {
 
     private static final String TAG = "GlobalActions";
-
-    private static final boolean SHOW_SILENT_TOGGLE = true;
-
-    /* Valid settings for global actions keys.
-     * see config.xml config_globalActionList */
-    private static final String GLOBAL_ACTION_KEY_POWER = "power";
-    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
-    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
-    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
-    private static final String GLOBAL_ACTION_KEY_USERS = "users";
-    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
-    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
-    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
-    private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
-    private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
-    private final WindowManagerFuncs mWindowManagerFuncs;
-    private final AudioManager mAudioManager;
-    private final IDreamManager mDreamManager;
+    private final LegacyGlobalActions mLegacyGlobalActions;
+    private final StatusBarManagerInternal mStatusBarInternal;
+    private final Handler mHandler;
+    private boolean mKeyguardShowing;
+    private boolean mDeviceProvisioned;
+    private boolean mStatusBarConnected;
+    private boolean mShowing;
 
-    private ArrayList<Action> mItems;
-    private GlobalActionsDialog mDialog;
-
-    private Action mSilentModeAction;
-    private ToggleAction mAirplaneModeOn;
-
-    private MyAdapter mAdapter;
-
-    private boolean mKeyguardShowing = false;
-    private boolean mDeviceProvisioned = false;
-    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
-    private boolean mIsWaitingForEcmExit = false;
-    private boolean mHasTelephony;
-    private boolean mHasVibrator;
-    private final boolean mShowSilentToggle;
-    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
-
-    /**
-     * @param context everything needs a context :(
-     */
     public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
         mContext = context;
-        mWindowManagerFuncs = windowManagerFuncs;
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.getService(DreamService.DREAM_SERVICE));
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter);
-
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        // get notified of phone state changes
-        TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
-                mAirplaneModeObserver);
-        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator != null && vibrator.hasVibrator();
-
-        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useFixedVolume);
-
-        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
+        mHandler = new Handler();
+        mLegacyGlobalActions = new LegacyGlobalActions(context, windowManagerFuncs,
+                this::onGlobalActionsDismissed);
+        mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
+        mStatusBarInternal.setGlobalActionsListener(this);
     }
 
-    /**
-     * Show the global actions dialog (creating if necessary)
-     * @param keyguardShowing True if keyguard is showing
-     */
-    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+    public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
+        if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
         mKeyguardShowing = keyguardShowing;
-        mDeviceProvisioned = isDeviceProvisioned;
-        if (mDialog != null) {
-            mDialog.dismiss();
-            mDialog = null;
-            // Show delayed, so that the dismiss of the previous dialog completes
-            mHandler.sendEmptyMessage(MESSAGE_SHOW);
+        mDeviceProvisioned = deviceProvisioned;
+        mShowing = true;
+        if (mStatusBarConnected) {
+            mStatusBarInternal.showGlobalActions();
+            mHandler.postDelayed(mShowTimeout, 5000);
         } else {
-            handleShow();
+            // SysUI isn't alive, show legacy menu.
+            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     }
 
-    private void awakenIfNecessary() {
-        if (mDreamManager != null) {
-            try {
-                if (mDreamManager.isDreaming()) {
-                    mDreamManager.awaken();
-                }
-            } catch (RemoteException e) {
-                // we tried
-            }
+    @Override
+    public void onGlobalActionsShown() {
+        if (DEBUG) Slog.d(TAG, "onGlobalActionsShown");
+        // SysUI is showing, remove timeout callbacks.
+        mHandler.removeCallbacks(mShowTimeout);
+    }
+
+    @Override
+    public void onGlobalActionsDismissed() {
+        if (DEBUG) Slog.d(TAG, "onGlobalActionsDismissed");
+        mShowing = false;
+    }
+
+    @Override
+    public void onStatusBarConnectedChanged(boolean connected) {
+        if (DEBUG) Slog.d(TAG, "onStatusBarConnectedChanged " + connected);
+        mStatusBarConnected = connected;
+        if (mShowing && !mStatusBarConnected) {
+            // Status bar died but we need to be showing global actions still, show the legacy.
+            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     }
 
-    private void handleShow() {
-        awakenIfNecessary();
-        mDialog = createDialog();
-        prepareDialog();
-
-        // If we only have 1 item and it's a simple press action, just do this action.
-        if (mAdapter.getCount() == 1
-                && mAdapter.getItem(0) instanceof SinglePressAction
-                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
-            ((SinglePressAction) mAdapter.getItem(0)).onPress();
-        } else {
-            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
-            attrs.setTitle("GlobalActions");
-            mDialog.getWindow().setAttributes(attrs);
-            mDialog.show();
-            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
-        }
-    }
-
-    /**
-     * Create the global actions dialog.
-     * @return A new dialog.
-     */
-    private GlobalActionsDialog createDialog() {
-        // Simple toggle style if there's no vibrator, otherwise use a tri-state
-        if (!mHasVibrator) {
-            mSilentModeAction = new SilentModeToggleAction();
-        } else {
-            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
-        }
-        mAirplaneModeOn = new ToggleAction(
-                R.drawable.ic_lock_airplane_mode,
-                R.drawable.ic_lock_airplane_mode_off,
-                R.string.global_actions_toggle_airplane_mode,
-                R.string.global_actions_airplane_mode_on_status,
-                R.string.global_actions_airplane_mode_off_status) {
-
-            void onToggle(boolean on) {
-                if (mHasTelephony && Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
-                    mIsWaitingForEcmExit = true;
-                    // Launch ECM exit dialog
-                    Intent ecmDialogIntent =
-                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
-                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivity(ecmDialogIntent);
-                } else {
-                    changeAirplaneModeSystemSetting(on);
-                }
-            }
-
-            @Override
-            protected void changeStateFromPress(boolean buttonOn) {
-                if (!mHasTelephony) return;
-
-                // In ECM mode airplane state cannot be changed
-                if (!(Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
-                    mState = buttonOn ? State.TurningOn : State.TurningOff;
-                    mAirplaneState = mState;
-                }
-            }
-
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-        };
-        onAirplaneModeChanged();
-
-        mItems = new ArrayList<Action>();
-        String[] defaultActions = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_globalActionsList);
-
-        ArraySet<String> addedKeys = new ArraySet<String>();
-        for (int i = 0; i < defaultActions.length; i++) {
-            String actionKey = defaultActions[i];
-            if (addedKeys.contains(actionKey)) {
-                // If we already have added this, don't add it again.
-                continue;
-            }
-            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
-                mItems.add(new PowerAction());
-            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
-                mItems.add(mAirplaneModeOn);
-            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
-                if (Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
-                    mItems.add(new BugReportAction());
-                }
-            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
-                if (mShowSilentToggle) {
-                    mItems.add(mSilentModeAction);
-                }
-            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
-                if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
-                    addUsersToMenu(mItems);
-                }
-            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
-                mItems.add(getSettingsAction());
-            } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
-                mItems.add(getLockdownAction());
-            } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
-                mItems.add(getVoiceAssistAction());
-            } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
-                mItems.add(getAssistAction());
-            } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
-                mItems.add(new RestartAction());
-            } else {
-                Log.e(TAG, "Invalid global action key " + actionKey);
-            }
-            // Add here so we don't add more than one.
-            addedKeys.add(actionKey);
-        }
-
-        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
-            mItems.add(getEmergencyAction());
-        }
-
-        mAdapter = new MyAdapter();
-
-        AlertParams params = new AlertParams(mContext);
-        params.mAdapter = mAdapter;
-        params.mOnClickListener = this;
-        params.mForceInverseBackground = true;
-
-        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
-        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
-
-        dialog.getListView().setItemsCanFocus(true);
-        dialog.getListView().setLongClickable(true);
-        dialog.getListView().setOnItemLongClickListener(
-                new AdapterView.OnItemLongClickListener() {
-                    @Override
-                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
-                            long id) {
-                        final Action action = mAdapter.getItem(position);
-                        if (action instanceof LongPressAction) {
-                            return ((LongPressAction) action).onLongPress();
-                        }
-                        return false;
-                    }
-        });
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-
-        dialog.setOnDismissListener(this);
-
-        return dialog;
-    }
-
-    private final class PowerAction extends SinglePressAction implements LongPressAction {
-        private PowerAction() {
-            super(com.android.internal.R.drawable.ic_lock_power_off,
-                R.string.global_action_power_off);
-        }
-
+    private final Runnable mShowTimeout = new Runnable() {
         @Override
-        public boolean onLongPress() {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
-                mWindowManagerFuncs.rebootSafeMode(true);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        @Override
-        public boolean showBeforeProvisioning() {
-            return true;
-        }
-
-        @Override
-        public void onPress() {
-            // shutdown by making sure radio and power are handled accordingly.
-            mWindowManagerFuncs.shutdown(false /* confirm */);
-        }
-    }
-
-    private final class RestartAction extends SinglePressAction implements LongPressAction {
-        private RestartAction() {
-            super(R.drawable.ic_restart, R.string.global_action_restart);
-        }
-
-        @Override
-        public boolean onLongPress() {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
-                mWindowManagerFuncs.rebootSafeMode(true);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        @Override
-        public boolean showBeforeProvisioning() {
-            return true;
-        }
-
-        @Override
-        public void onPress() {
-            mWindowManagerFuncs.reboot(false /* confirm */);
-        }
-    }
-
-
-    private class BugReportAction extends SinglePressAction implements LongPressAction {
-
-        public BugReportAction() {
-            super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
-        }
-
-        @Override
-        public void onPress() {
-            // don't actually trigger the bugreport if we are running stability
-            // tests via monkey
-            if (ActivityManager.isUserAMonkey()) {
-                return;
-            }
-            // Add a little delay before executing, to give the
-            // dialog a chance to go away before it takes a
-            // screenshot.
-            mHandler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        // Take an "interactive" bugreport.
-                        MetricsLogger.action(mContext,
-                                MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
-                        ActivityManager.getService().requestBugReport(
-                                ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }, 500);
-        }
-
-        @Override
-        public boolean onLongPress() {
-            // don't actually trigger the bugreport if we are running stability
-            // tests via monkey
-            if (ActivityManager.isUserAMonkey()) {
-                return false;
-            }
-            try {
-                // Take a "full" bugreport.
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
-                ActivityManager.getService().requestBugReport(
-                        ActivityManager.BUGREPORT_OPTION_FULL);
-            } catch (RemoteException e) {
-            }
-            return false;
-        }
-
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        @Override
-        public boolean showBeforeProvisioning() {
-            return false;
-        }
-
-        @Override
-        public String getStatus() {
-            return mContext.getString(
-                    com.android.internal.R.string.bugreport_status,
-                    Build.VERSION.RELEASE,
-                    Build.ID);
-        }
-    }
-
-    private Action getSettingsAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
-                R.string.global_action_settings) {
-
-            @Override
-            public void onPress() {
-                Intent intent = new Intent(Settings.ACTION_SETTINGS);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivity(intent);
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return true;
-            }
-        };
-    }
-
-    private Action getEmergencyAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
-                R.string.global_action_emergency) {
-            @Override
-            public void onPress() {
-                mEmergencyAffordanceManager.performEmergencyCall();
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return true;
-            }
-        };
-    }
-
-    private Action getAssistAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
-                R.string.global_action_assist) {
-            @Override
-            public void onPress() {
-                Intent intent = new Intent(Intent.ACTION_ASSIST);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivity(intent);
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return true;
-            }
-        };
-    }
-
-    private Action getVoiceAssistAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
-                R.string.global_action_voice_assist) {
-            @Override
-            public void onPress() {
-                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivity(intent);
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return true;
-            }
-        };
-    }
-
-    private Action getLockdownAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
-                R.string.global_action_lockdown) {
-
-            @Override
-            public void onPress() {
-                new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
-                try {
-                    WindowManagerGlobal.getWindowManagerService().lockNow(null);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error while trying to lock device.", e);
-                }
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-        };
-    }
-
-    private UserInfo getCurrentUser() {
-        try {
-            return ActivityManager.getService().getCurrentUser();
-        } catch (RemoteException re) {
-            return null;
-        }
-    }
-
-    private boolean isCurrentUserOwner() {
-        UserInfo currentUser = getCurrentUser();
-        return currentUser == null || currentUser.isPrimary();
-    }
-
-    private void addUsersToMenu(ArrayList<Action> items) {
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.isUserSwitcherEnabled()) {
-            List<UserInfo> users = um.getUsers();
-            UserInfo currentUser = getCurrentUser();
-            for (final UserInfo user : users) {
-                if (user.supportsSwitchToByUser()) {
-                    boolean isCurrentUser = currentUser == null
-                            ? user.id == 0 : (currentUser.id == user.id);
-                    Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
-                            : null;
-                    SinglePressAction switchToUser = new SinglePressAction(
-                            com.android.internal.R.drawable.ic_menu_cc, icon,
-                            (user.name != null ? user.name : "Primary")
-                            + (isCurrentUser ? " \u2714" : "")) {
-                        public void onPress() {
-                            try {
-                                ActivityManager.getService().switchUser(user.id);
-                            } catch (RemoteException re) {
-                                Log.e(TAG, "Couldn't switch user " + re);
-                            }
-                        }
-
-                        public boolean showDuringKeyguard() {
-                            return true;
-                        }
-
-                        public boolean showBeforeProvisioning() {
-                            return false;
-                        }
-                    };
-                    items.add(switchToUser);
-                }
-            }
-        }
-    }
-
-    private void prepareDialog() {
-        refreshSilentMode();
-        mAirplaneModeOn.updateState(mAirplaneState);
-        mAdapter.notifyDataSetChanged();
-        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        if (mShowSilentToggle) {
-            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            mContext.registerReceiver(mRingerModeReceiver, filter);
-        }
-    }
-
-    private void refreshSilentMode() {
-        if (!mHasVibrator) {
-            final boolean silentModeOn =
-                    mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
-            ((ToggleAction)mSilentModeAction).updateState(
-                    silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void onDismiss(DialogInterface dialog) {
-        if (mShowSilentToggle) {
-            try {
-                mContext.unregisterReceiver(mRingerModeReceiver);
-            } catch (IllegalArgumentException ie) {
-                // ignore this
-                Log.w(TAG, ie);
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void onClick(DialogInterface dialog, int which) {
-        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
-            dialog.dismiss();
-        }
-        mAdapter.getItem(which).onPress();
-    }
-
-    /**
-     * The adapter used for the list within the global actions dialog, taking
-     * into account whether the keyguard is showing via
-     * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
-     * via {@link GlobalActions#mDeviceProvisioned}.
-     */
-    private class MyAdapter extends BaseAdapter {
-
-        public int getCount() {
-            int count = 0;
-
-            for (int i = 0; i < mItems.size(); i++) {
-                final Action action = mItems.get(i);
-
-                if (mKeyguardShowing && !action.showDuringKeyguard()) {
-                    continue;
-                }
-                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
-                    continue;
-                }
-                count++;
-            }
-            return count;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            return getItem(position).isEnabled();
-        }
-
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        public Action getItem(int position) {
-
-            int filteredPos = 0;
-            for (int i = 0; i < mItems.size(); i++) {
-                final Action action = mItems.get(i);
-                if (mKeyguardShowing && !action.showDuringKeyguard()) {
-                    continue;
-                }
-                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
-                    continue;
-                }
-                if (filteredPos == position) {
-                    return action;
-                }
-                filteredPos++;
-            }
-
-            throw new IllegalArgumentException("position " + position
-                    + " out of range of showable actions"
-                    + ", filtered count=" + getCount()
-                    + ", keyguardshowing=" + mKeyguardShowing
-                    + ", provisioned=" + mDeviceProvisioned);
-        }
-
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            Action action = getItem(position);
-            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
-        }
-    }
-
-    // note: the scheme below made more sense when we were planning on having
-    // 8 different things in the global actions dialog.  seems overkill with
-    // only 3 items now, but may as well keep this flexible approach so it will
-    // be easy should someone decide at the last minute to include something
-    // else, such as 'enable wifi', or 'enable bluetooth'
-
-    /**
-     * What each item in the global actions dialog must be able to support.
-     */
-    private interface Action {
-        /**
-         * @return Text that will be announced when dialog is created.  null
-         *     for none.
-         */
-        CharSequence getLabelForAccessibility(Context context);
-
-        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
-
-        void onPress();
-
-        /**
-         * @return whether this action should appear in the dialog when the keygaurd
-         *    is showing.
-         */
-        boolean showDuringKeyguard();
-
-        /**
-         * @return whether this action should appear in the dialog before the
-         *   device is provisioned.
-         */
-        boolean showBeforeProvisioning();
-
-        boolean isEnabled();
-    }
-
-    /**
-     * An action that also supports long press.
-     */
-    private interface LongPressAction extends Action {
-        boolean onLongPress();
-    }
-
-    /**
-     * A single press action maintains no state, just responds to a press
-     * and takes an action.
-     */
-    private static abstract class SinglePressAction implements Action {
-        private final int mIconResId;
-        private final Drawable mIcon;
-        private final int mMessageResId;
-        private final CharSequence mMessage;
-
-        protected SinglePressAction(int iconResId, int messageResId) {
-            mIconResId = iconResId;
-            mMessageResId = messageResId;
-            mMessage = null;
-            mIcon = null;
-        }
-
-        protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
-            mIconResId = iconResId;
-            mMessageResId = 0;
-            mMessage = message;
-            mIcon = icon;
-        }
-
-        public boolean isEnabled() {
-            return true;
-        }
-
-        public String getStatus() {
-            return null;
-        }
-
-        abstract public void onPress();
-
-        public CharSequence getLabelForAccessibility(Context context) {
-            if (mMessage != null) {
-                return mMessage;
-            } else {
-                return context.getString(mMessageResId);
-            }
-        }
-
-        public View create(
-                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
-            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
-
-            ImageView icon = (ImageView) v.findViewById(R.id.icon);
-            TextView messageView = (TextView) v.findViewById(R.id.message);
-
-            TextView statusView = (TextView) v.findViewById(R.id.status);
-            final String status = getStatus();
-            if (!TextUtils.isEmpty(status)) {
-                statusView.setText(status);
-            } else {
-                statusView.setVisibility(View.GONE);
-            }
-            if (mIcon != null) {
-                icon.setImageDrawable(mIcon);
-                icon.setScaleType(ScaleType.CENTER_CROP);
-            } else if (mIconResId != 0) {
-                icon.setImageDrawable(context.getDrawable(mIconResId));
-            }
-            if (mMessage != null) {
-                messageView.setText(mMessage);
-            } else {
-                messageView.setText(mMessageResId);
-            }
-
-            return v;
-        }
-    }
-
-    /**
-     * A toggle action knows whether it is on or off, and displays an icon
-     * and status message accordingly.
-     */
-    private static abstract class ToggleAction implements Action {
-
-        enum State {
-            Off(false),
-            TurningOn(true),
-            TurningOff(true),
-            On(false);
-
-            private final boolean inTransition;
-
-            State(boolean intermediate) {
-                inTransition = intermediate;
-            }
-
-            public boolean inTransition() {
-                return inTransition;
-            }
-        }
-
-        protected State mState = State.Off;
-
-        // prefs
-        protected int mEnabledIconResId;
-        protected int mDisabledIconResid;
-        protected int mMessageResId;
-        protected int mEnabledStatusMessageResId;
-        protected int mDisabledStatusMessageResId;
-
-        /**
-         * @param enabledIconResId The icon for when this action is on.
-         * @param disabledIconResid The icon for when this action is off.
-         * @param essage The general information message, e.g 'Silent Mode'
-         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
-         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
-         */
-        public ToggleAction(int enabledIconResId,
-                int disabledIconResid,
-                int message,
-                int enabledStatusMessageResId,
-                int disabledStatusMessageResId) {
-            mEnabledIconResId = enabledIconResId;
-            mDisabledIconResid = disabledIconResid;
-            mMessageResId = message;
-            mEnabledStatusMessageResId = enabledStatusMessageResId;
-            mDisabledStatusMessageResId = disabledStatusMessageResId;
-        }
-
-        /**
-         * Override to make changes to resource IDs just before creating the
-         * View.
-         */
-        void willCreate() {
-
-        }
-
-        @Override
-        public CharSequence getLabelForAccessibility(Context context) {
-            return context.getString(mMessageResId);
-        }
-
-        public View create(Context context, View convertView, ViewGroup parent,
-                LayoutInflater inflater) {
-            willCreate();
-
-            View v = inflater.inflate(R
-                            .layout.global_actions_item, parent, false);
-
-            ImageView icon = (ImageView) v.findViewById(R.id.icon);
-            TextView messageView = (TextView) v.findViewById(R.id.message);
-            TextView statusView = (TextView) v.findViewById(R.id.status);
-            final boolean enabled = isEnabled();
-
-            if (messageView != null) {
-                messageView.setText(mMessageResId);
-                messageView.setEnabled(enabled);
-            }
-
-            boolean on = ((mState == State.On) || (mState == State.TurningOn));
-            if (icon != null) {
-                icon.setImageDrawable(context.getDrawable(
-                        (on ? mEnabledIconResId : mDisabledIconResid)));
-                icon.setEnabled(enabled);
-            }
-
-            if (statusView != null) {
-                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
-                statusView.setVisibility(View.VISIBLE);
-                statusView.setEnabled(enabled);
-            }
-            v.setEnabled(enabled);
-
-            return v;
-        }
-
-        public final void onPress() {
-            if (mState.inTransition()) {
-                Log.w(TAG, "shouldn't be able to toggle when in transition");
-                return;
-            }
-
-            final boolean nowOn = !(mState == State.On);
-            onToggle(nowOn);
-            changeStateFromPress(nowOn);
-        }
-
-        public boolean isEnabled() {
-            return !mState.inTransition();
-        }
-
-        /**
-         * Implementations may override this if their state can be in on of the intermediate
-         * states until some notification is received (e.g airplane mode is 'turning off' until
-         * we know the wireless connections are back online
-         * @param buttonOn Whether the button was turned on or off
-         */
-        protected void changeStateFromPress(boolean buttonOn) {
-            mState = buttonOn ? State.On : State.Off;
-        }
-
-        abstract void onToggle(boolean on);
-
-        public void updateState(State state) {
-            mState = state;
-        }
-    }
-
-    private class SilentModeToggleAction extends ToggleAction {
-        public SilentModeToggleAction() {
-            super(R.drawable.ic_audio_vol_mute,
-                    R.drawable.ic_audio_vol,
-                    R.string.global_action_toggle_silent_mode,
-                    R.string.global_action_silent_mode_on_status,
-                    R.string.global_action_silent_mode_off_status);
-        }
-
-        void onToggle(boolean on) {
-            if (on) {
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
-            } else {
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-            }
-        }
-
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        public boolean showBeforeProvisioning() {
-            return false;
-        }
-    }
-
-    private static class SilentModeTriStateAction implements Action, View.OnClickListener {
-
-        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
-
-        private final AudioManager mAudioManager;
-        private final Handler mHandler;
-        private final Context mContext;
-
-        SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
-            mAudioManager = audioManager;
-            mHandler = handler;
-            mContext = context;
-        }
-
-        private int ringerModeToIndex(int ringerMode) {
-            // They just happen to coincide
-            return ringerMode;
-        }
-
-        private int indexToRingerMode(int index) {
-            // They just happen to coincide
-            return index;
-        }
-
-        @Override
-        public CharSequence getLabelForAccessibility(Context context) {
-            return null;
-        }
-
-        public View create(Context context, View convertView, ViewGroup parent,
-                LayoutInflater inflater) {
-            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
-
-            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
-            for (int i = 0; i < 3; i++) {
-                View itemView = v.findViewById(ITEM_IDS[i]);
-                itemView.setSelected(selectedIndex == i);
-                // Set up click handler
-                itemView.setTag(i);
-                itemView.setOnClickListener(this);
-            }
-            return v;
-        }
-
-        public void onPress() {
-        }
-
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        public boolean showBeforeProvisioning() {
-            return false;
-        }
-
-        public boolean isEnabled() {
-            return true;
-        }
-
-        void willCreate() {
-        }
-
-        public void onClick(View v) {
-            if (!(v.getTag() instanceof Integer)) return;
-
-            int index = (Integer) v.getTag();
-            mAudioManager.setRingerMode(indexToRingerMode(index));
-            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
-        }
-    }
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
-                if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
-                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
-                }
-            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
-                // Airplane mode can be changed after ECM exits if airplane toggle button
-                // is pressed during ECM mode
-                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
-                        mIsWaitingForEcmExit) {
-                    mIsWaitingForEcmExit = false;
-                    changeAirplaneModeSystemSetting(true);
-                }
-            }
+        public void run() {
+            if (DEBUG) Slog.d(TAG, "Global actions timeout");
+            // We haven't heard from sysui, show the legacy dialog.
+            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
         }
     };
-
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onServiceStateChanged(ServiceState serviceState) {
-            if (!mHasTelephony) return;
-            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
-            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
-            mAirplaneModeOn.updateState(mAirplaneState);
-            mAdapter.notifyDataSetChanged();
-        }
-    };
-
-    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
-                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
-            }
-        }
-    };
-
-    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            onAirplaneModeChanged();
-        }
-    };
-
-    private static final int MESSAGE_DISMISS = 0;
-    private static final int MESSAGE_REFRESH = 1;
-    private static final int MESSAGE_SHOW = 2;
-    private static final int DIALOG_DISMISS_DELAY = 300; // ms
-
-    private Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case MESSAGE_DISMISS:
-                if (mDialog != null) {
-                    mDialog.dismiss();
-                    mDialog = null;
-                }
-                break;
-            case MESSAGE_REFRESH:
-                refreshSilentMode();
-                mAdapter.notifyDataSetChanged();
-                break;
-            case MESSAGE_SHOW:
-                handleShow();
-                break;
-            }
-        }
-    };
-
-    private void onAirplaneModeChanged() {
-        // Let the service state callbacks handle the state.
-        if (mHasTelephony) return;
-
-        boolean airplaneModeOn = Settings.Global.getInt(
-                mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON,
-                0) == 1;
-        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
-        mAirplaneModeOn.updateState(mAirplaneState);
-    }
-
-    /**
-     * Change the airplane mode system setting
-     */
-    private void changeAirplaneModeSystemSetting(boolean on) {
-        Settings.Global.putInt(
-                mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON,
-                on ? 1 : 0);
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("state", on);
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-        if (!mHasTelephony) {
-            mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
-        }
-    }
-
-    private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
-        private final Context mContext;
-        private final AlertController mAlert;
-        private final MyAdapter mAdapter;
-
-        public GlobalActionsDialog(Context context, AlertParams params) {
-            super(context, getDialogTheme(context));
-            mContext = getContext();
-            mAlert = AlertController.create(mContext, this, getWindow());
-            mAdapter = (MyAdapter) params.mAdapter;
-            params.apply(mAlert);
-        }
-
-        private static int getDialogTheme(Context context) {
-            TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
-                    outValue, true);
-            return outValue.resourceId;
-        }
-
-        @Override
-        protected void onStart() {
-            super.setCanceledOnTouchOutside(true);
-            super.onStart();
-        }
-
-        public ListView getListView() {
-            return mAlert.getListView();
-        }
-
-        @Override
-        protected void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mAlert.installContent();
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-                for (int i = 0; i < mAdapter.getCount(); ++i) {
-                    CharSequence label =
-                            mAdapter.getItem(i).getLabelForAccessibility(getContext());
-                    if (label != null) {
-                        event.getText().add(label);
-                    }
-                }
-            }
-            return super.dispatchPopulateAccessibilityEvent(event);
-        }
-
-        @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            if (mAlert.onKeyDown(keyCode, event)) {
-                return true;
-            }
-            return super.onKeyDown(keyCode, event);
-        }
-
-        @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            if (mAlert.onKeyUp(keyCode, event)) {
-                return true;
-            }
-            return super.onKeyUp(keyCode, event);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
new file mode 100644
index 0000000..a71bc4c
--- /dev/null
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import com.android.internal.app.AlertController;
+import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.ActivityManager;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicy.WindowManagerFuncs;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper to show the global actions dialog.  Each item is an {@link Action} that
+ * may show depending on whether the keyguard is showing, and whether the device
+ * is provisioned.
+ */
+class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
+
+    private static final String TAG = "LegacyGlobalActions";
+
+    private static final boolean SHOW_SILENT_TOGGLE = true;
+
+    /* Valid settings for global actions keys.
+     * see config.xml config_globalActionList */
+    private static final String GLOBAL_ACTION_KEY_POWER = "power";
+    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+    private static final String GLOBAL_ACTION_KEY_USERS = "users";
+    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+    private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
+    private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+
+    private final Context mContext;
+    private final WindowManagerFuncs mWindowManagerFuncs;
+    private final AudioManager mAudioManager;
+    private final IDreamManager mDreamManager;
+    private final Runnable mOnDismiss;
+
+    private ArrayList<Action> mItems;
+    private GlobalActionsDialog mDialog;
+
+    private Action mSilentModeAction;
+    private ToggleAction mAirplaneModeOn;
+
+    private MyAdapter mAdapter;
+
+    private boolean mKeyguardShowing = false;
+    private boolean mDeviceProvisioned = false;
+    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
+    private boolean mIsWaitingForEcmExit = false;
+    private boolean mHasTelephony;
+    private boolean mHasVibrator;
+    private final boolean mShowSilentToggle;
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
+
+    /**
+     * @param context everything needs a context :(
+     */
+    public LegacyGlobalActions(Context context, WindowManagerFuncs windowManagerFuncs,
+            Runnable onDismiss) {
+        mContext = context;
+        mWindowManagerFuncs = windowManagerFuncs;
+        mOnDismiss = onDismiss;
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.getService(DreamService.DREAM_SERVICE));
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        context.registerReceiver(mBroadcastReceiver, filter);
+
+        ConnectivityManager cm = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        // get notified of phone state changes
+        TelephonyManager telephonyManager =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
+                mAirplaneModeObserver);
+        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = vibrator != null && vibrator.hasVibrator();
+
+        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
+
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
+    }
+
+    /**
+     * Show the global actions dialog (creating if necessary)
+     * @param keyguardShowing True if keyguard is showing
+     */
+    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+        mKeyguardShowing = keyguardShowing;
+        mDeviceProvisioned = isDeviceProvisioned;
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+            // Show delayed, so that the dismiss of the previous dialog completes
+            mHandler.sendEmptyMessage(MESSAGE_SHOW);
+        } else {
+            handleShow();
+        }
+    }
+
+    private void awakenIfNecessary() {
+        if (mDreamManager != null) {
+            try {
+                if (mDreamManager.isDreaming()) {
+                    mDreamManager.awaken();
+                }
+            } catch (RemoteException e) {
+                // we tried
+            }
+        }
+    }
+
+    private void handleShow() {
+        awakenIfNecessary();
+        mDialog = createDialog();
+        prepareDialog();
+
+        // If we only have 1 item and it's a simple press action, just do this action.
+        if (mAdapter.getCount() == 1
+                && mAdapter.getItem(0) instanceof SinglePressAction
+                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
+            ((SinglePressAction) mAdapter.getItem(0)).onPress();
+        } else {
+            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+            attrs.setTitle("LegacyGlobalActions");
+            mDialog.getWindow().setAttributes(attrs);
+            mDialog.show();
+            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+        }
+    }
+
+    /**
+     * Create the global actions dialog.
+     * @return A new dialog.
+     */
+    private GlobalActionsDialog createDialog() {
+        // Simple toggle style if there's no vibrator, otherwise use a tri-state
+        if (!mHasVibrator) {
+            mSilentModeAction = new SilentModeToggleAction();
+        } else {
+            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
+        }
+        mAirplaneModeOn = new ToggleAction(
+                R.drawable.ic_lock_airplane_mode,
+                R.drawable.ic_lock_airplane_mode_off,
+                R.string.global_actions_toggle_airplane_mode,
+                R.string.global_actions_airplane_mode_on_status,
+                R.string.global_actions_airplane_mode_off_status) {
+
+            void onToggle(boolean on) {
+                if (mHasTelephony && Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                    mIsWaitingForEcmExit = true;
+                    // Launch ECM exit dialog
+                    Intent ecmDialogIntent =
+                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivity(ecmDialogIntent);
+                } else {
+                    changeAirplaneModeSystemSetting(on);
+                }
+            }
+
+            @Override
+            protected void changeStateFromPress(boolean buttonOn) {
+                if (!mHasTelephony) return;
+
+                // In ECM mode airplane state cannot be changed
+                if (!(Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                    mState = buttonOn ? State.TurningOn : State.TurningOff;
+                    mAirplaneState = mState;
+                }
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+        onAirplaneModeChanged();
+
+        mItems = new ArrayList<Action>();
+        String[] defaultActions = mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_globalActionsList);
+
+        ArraySet<String> addedKeys = new ArraySet<String>();
+        for (int i = 0; i < defaultActions.length; i++) {
+            String actionKey = defaultActions[i];
+            if (addedKeys.contains(actionKey)) {
+                // If we already have added this, don't add it again.
+                continue;
+            }
+            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+                mItems.add(new PowerAction());
+            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+                mItems.add(mAirplaneModeOn);
+            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
+                if (Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
+                    mItems.add(new BugReportAction());
+                }
+            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
+                if (mShowSilentToggle) {
+                    mItems.add(mSilentModeAction);
+                }
+            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
+                if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+                    addUsersToMenu(mItems);
+                }
+            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+                mItems.add(getSettingsAction());
+            } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
+                mItems.add(getLockdownAction());
+            } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
+                mItems.add(getVoiceAssistAction());
+            } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
+                mItems.add(getAssistAction());
+            } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
+                mItems.add(new RestartAction());
+            } else {
+                Log.e(TAG, "Invalid global action key " + actionKey);
+            }
+            // Add here so we don't add more than one.
+            addedKeys.add(actionKey);
+        }
+
+        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+            mItems.add(getEmergencyAction());
+        }
+
+        mAdapter = new MyAdapter();
+
+        AlertParams params = new AlertParams(mContext);
+        params.mAdapter = mAdapter;
+        params.mOnClickListener = this;
+        params.mForceInverseBackground = true;
+
+        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
+        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
+
+        dialog.getListView().setItemsCanFocus(true);
+        dialog.getListView().setLongClickable(true);
+        dialog.getListView().setOnItemLongClickListener(
+                new AdapterView.OnItemLongClickListener() {
+                    @Override
+                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
+                            long id) {
+                        final Action action = mAdapter.getItem(position);
+                        if (action instanceof LongPressAction) {
+                            return ((LongPressAction) action).onLongPress();
+                        }
+                        return false;
+                    }
+        });
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+
+        dialog.setOnDismissListener(this);
+
+        return dialog;
+    }
+
+    private final class PowerAction extends SinglePressAction implements LongPressAction {
+        private PowerAction() {
+            super(com.android.internal.R.drawable.ic_lock_power_off,
+                R.string.global_action_power_off);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+                mWindowManagerFuncs.rebootSafeMode(true);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            // shutdown by making sure radio and power are handled accordingly.
+            mWindowManagerFuncs.shutdown(false /* confirm */);
+        }
+    }
+
+    private final class RestartAction extends SinglePressAction implements LongPressAction {
+        private RestartAction() {
+            super(R.drawable.ic_restart, R.string.global_action_restart);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+                mWindowManagerFuncs.rebootSafeMode(true);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            mWindowManagerFuncs.reboot(false /* confirm */);
+        }
+    }
+
+
+    private class BugReportAction extends SinglePressAction implements LongPressAction {
+
+        public BugReportAction() {
+            super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
+        }
+
+        @Override
+        public void onPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
+                return;
+            }
+            // Add a little delay before executing, to give the
+            // dialog a chance to go away before it takes a
+            // screenshot.
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        // Take an "interactive" bugreport.
+                        MetricsLogger.action(mContext,
+                                MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
+                        ActivityManager.getService().requestBugReport(
+                                ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }, 500);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
+                return false;
+            }
+            try {
+                // Take a "full" bugreport.
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
+                ActivityManager.getService().requestBugReport(
+                        ActivityManager.BUGREPORT_OPTION_FULL);
+            } catch (RemoteException e) {
+            }
+            return false;
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        @Override
+        public String getStatus() {
+            return mContext.getString(
+                    com.android.internal.R.string.bugreport_status,
+                    Build.VERSION.RELEASE,
+                    Build.ID);
+        }
+    }
+
+    private Action getSettingsAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+                R.string.global_action_settings) {
+
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Settings.ACTION_SETTINGS);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getEmergencyAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
+                R.string.global_action_emergency) {
+            @Override
+            public void onPress() {
+                mEmergencyAffordanceManager.performEmergencyCall();
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getAssistAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
+                R.string.global_action_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getVoiceAssistAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
+                R.string.global_action_voice_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getLockdownAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
+                R.string.global_action_lockdown) {
+
+            @Override
+            public void onPress() {
+                new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+                try {
+                    WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error while trying to lock device.", e);
+                }
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+    }
+
+    private UserInfo getCurrentUser() {
+        try {
+            return ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    private boolean isCurrentUserOwner() {
+        UserInfo currentUser = getCurrentUser();
+        return currentUser == null || currentUser.isPrimary();
+    }
+
+    private void addUsersToMenu(ArrayList<Action> items) {
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (um.isUserSwitcherEnabled()) {
+            List<UserInfo> users = um.getUsers();
+            UserInfo currentUser = getCurrentUser();
+            for (final UserInfo user : users) {
+                if (user.supportsSwitchToByUser()) {
+                    boolean isCurrentUser = currentUser == null
+                            ? user.id == 0 : (currentUser.id == user.id);
+                    Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
+                            : null;
+                    SinglePressAction switchToUser = new SinglePressAction(
+                            com.android.internal.R.drawable.ic_menu_cc, icon,
+                            (user.name != null ? user.name : "Primary")
+                            + (isCurrentUser ? " \u2714" : "")) {
+                        public void onPress() {
+                            try {
+                                ActivityManager.getService().switchUser(user.id);
+                            } catch (RemoteException re) {
+                                Log.e(TAG, "Couldn't switch user " + re);
+                            }
+                        }
+
+                        public boolean showDuringKeyguard() {
+                            return true;
+                        }
+
+                        public boolean showBeforeProvisioning() {
+                            return false;
+                        }
+                    };
+                    items.add(switchToUser);
+                }
+            }
+        }
+    }
+
+    private void prepareDialog() {
+        refreshSilentMode();
+        mAirplaneModeOn.updateState(mAirplaneState);
+        mAdapter.notifyDataSetChanged();
+        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        if (mShowSilentToggle) {
+            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mRingerModeReceiver, filter);
+        }
+    }
+
+    private void refreshSilentMode() {
+        if (!mHasVibrator) {
+            final boolean silentModeOn =
+                    mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
+            ((ToggleAction)mSilentModeAction).updateState(
+                    silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onDismiss(DialogInterface dialog) {
+        if (mOnDismiss != null) {
+            mOnDismiss.run();
+        }
+        if (mShowSilentToggle) {
+            try {
+                mContext.unregisterReceiver(mRingerModeReceiver);
+            } catch (IllegalArgumentException ie) {
+                // ignore this
+                Log.w(TAG, ie);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onClick(DialogInterface dialog, int which) {
+        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
+            dialog.dismiss();
+        }
+        mAdapter.getItem(which).onPress();
+    }
+
+    /**
+     * The adapter used for the list within the global actions dialog, taking
+     * into account whether the keyguard is showing via
+     * {@link LegacyGlobalActions#mKeyguardShowing} and whether the device is provisioned
+     * via {@link LegacyGlobalActions#mDeviceProvisioned}.
+     */
+    private class MyAdapter extends BaseAdapter {
+
+        public int getCount() {
+            int count = 0;
+
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                count++;
+            }
+            return count;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItem(position).isEnabled();
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        public Action getItem(int position) {
+
+            int filteredPos = 0;
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                if (filteredPos == position) {
+                    return action;
+                }
+                filteredPos++;
+            }
+
+            throw new IllegalArgumentException("position " + position
+                    + " out of range of showable actions"
+                    + ", filtered count=" + getCount()
+                    + ", keyguardshowing=" + mKeyguardShowing
+                    + ", provisioned=" + mDeviceProvisioned);
+        }
+
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            Action action = getItem(position);
+            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
+        }
+    }
+
+    // note: the scheme below made more sense when we were planning on having
+    // 8 different things in the global actions dialog.  seems overkill with
+    // only 3 items now, but may as well keep this flexible approach so it will
+    // be easy should someone decide at the last minute to include something
+    // else, such as 'enable wifi', or 'enable bluetooth'
+
+    /**
+     * What each item in the global actions dialog must be able to support.
+     */
+    private interface Action {
+        /**
+         * @return Text that will be announced when dialog is created.  null
+         *     for none.
+         */
+        CharSequence getLabelForAccessibility(Context context);
+
+        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
+
+        void onPress();
+
+        /**
+         * @return whether this action should appear in the dialog when the keygaurd
+         *    is showing.
+         */
+        boolean showDuringKeyguard();
+
+        /**
+         * @return whether this action should appear in the dialog before the
+         *   device is provisioned.
+         */
+        boolean showBeforeProvisioning();
+
+        boolean isEnabled();
+    }
+
+    /**
+     * An action that also supports long press.
+     */
+    private interface LongPressAction extends Action {
+        boolean onLongPress();
+    }
+
+    /**
+     * A single press action maintains no state, just responds to a press
+     * and takes an action.
+     */
+    private static abstract class SinglePressAction implements Action {
+        private final int mIconResId;
+        private final Drawable mIcon;
+        private final int mMessageResId;
+        private final CharSequence mMessage;
+
+        protected SinglePressAction(int iconResId, int messageResId) {
+            mIconResId = iconResId;
+            mMessageResId = messageResId;
+            mMessage = null;
+            mIcon = null;
+        }
+
+        protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
+            mIconResId = iconResId;
+            mMessageResId = 0;
+            mMessage = message;
+            mIcon = icon;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        public String getStatus() {
+            return null;
+        }
+
+        abstract public void onPress();
+
+        public CharSequence getLabelForAccessibility(Context context) {
+            if (mMessage != null) {
+                return mMessage;
+            } else {
+                return context.getString(mMessageResId);
+            }
+        }
+
+        public View create(
+                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final String status = getStatus();
+            if (!TextUtils.isEmpty(status)) {
+                statusView.setText(status);
+            } else {
+                statusView.setVisibility(View.GONE);
+            }
+            if (mIcon != null) {
+                icon.setImageDrawable(mIcon);
+                icon.setScaleType(ScaleType.CENTER_CROP);
+            } else if (mIconResId != 0) {
+                icon.setImageDrawable(context.getDrawable(mIconResId));
+            }
+            if (mMessage != null) {
+                messageView.setText(mMessage);
+            } else {
+                messageView.setText(mMessageResId);
+            }
+
+            return v;
+        }
+    }
+
+    /**
+     * A toggle action knows whether it is on or off, and displays an icon
+     * and status message accordingly.
+     */
+    private static abstract class ToggleAction implements Action {
+
+        enum State {
+            Off(false),
+            TurningOn(true),
+            TurningOff(true),
+            On(false);
+
+            private final boolean inTransition;
+
+            State(boolean intermediate) {
+                inTransition = intermediate;
+            }
+
+            public boolean inTransition() {
+                return inTransition;
+            }
+        }
+
+        protected State mState = State.Off;
+
+        // prefs
+        protected int mEnabledIconResId;
+        protected int mDisabledIconResid;
+        protected int mMessageResId;
+        protected int mEnabledStatusMessageResId;
+        protected int mDisabledStatusMessageResId;
+
+        /**
+         * @param enabledIconResId The icon for when this action is on.
+         * @param disabledIconResid The icon for when this action is off.
+         * @param essage The general information message, e.g 'Silent Mode'
+         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
+         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
+         */
+        public ToggleAction(int enabledIconResId,
+                int disabledIconResid,
+                int message,
+                int enabledStatusMessageResId,
+                int disabledStatusMessageResId) {
+            mEnabledIconResId = enabledIconResId;
+            mDisabledIconResid = disabledIconResid;
+            mMessageResId = message;
+            mEnabledStatusMessageResId = enabledStatusMessageResId;
+            mDisabledStatusMessageResId = disabledStatusMessageResId;
+        }
+
+        /**
+         * Override to make changes to resource IDs just before creating the
+         * View.
+         */
+        void willCreate() {
+
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return context.getString(mMessageResId);
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            willCreate();
+
+            View v = inflater.inflate(R
+                            .layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final boolean enabled = isEnabled();
+
+            if (messageView != null) {
+                messageView.setText(mMessageResId);
+                messageView.setEnabled(enabled);
+            }
+
+            boolean on = ((mState == State.On) || (mState == State.TurningOn));
+            if (icon != null) {
+                icon.setImageDrawable(context.getDrawable(
+                        (on ? mEnabledIconResId : mDisabledIconResid)));
+                icon.setEnabled(enabled);
+            }
+
+            if (statusView != null) {
+                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+                statusView.setVisibility(View.VISIBLE);
+                statusView.setEnabled(enabled);
+            }
+            v.setEnabled(enabled);
+
+            return v;
+        }
+
+        public final void onPress() {
+            if (mState.inTransition()) {
+                Log.w(TAG, "shouldn't be able to toggle when in transition");
+                return;
+            }
+
+            final boolean nowOn = !(mState == State.On);
+            onToggle(nowOn);
+            changeStateFromPress(nowOn);
+        }
+
+        public boolean isEnabled() {
+            return !mState.inTransition();
+        }
+
+        /**
+         * Implementations may override this if their state can be in on of the intermediate
+         * states until some notification is received (e.g airplane mode is 'turning off' until
+         * we know the wireless connections are back online
+         * @param buttonOn Whether the button was turned on or off
+         */
+        protected void changeStateFromPress(boolean buttonOn) {
+            mState = buttonOn ? State.On : State.Off;
+        }
+
+        abstract void onToggle(boolean on);
+
+        public void updateState(State state) {
+            mState = state;
+        }
+    }
+
+    private class SilentModeToggleAction extends ToggleAction {
+        public SilentModeToggleAction() {
+            super(R.drawable.ic_audio_vol_mute,
+                    R.drawable.ic_audio_vol,
+                    R.string.global_action_toggle_silent_mode,
+                    R.string.global_action_silent_mode_on_status,
+                    R.string.global_action_silent_mode_off_status);
+        }
+
+        void onToggle(boolean on) {
+            if (on) {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+            } else {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+            }
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+    }
+
+    private static class SilentModeTriStateAction implements Action, View.OnClickListener {
+
+        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+
+        private final AudioManager mAudioManager;
+        private final Handler mHandler;
+        private final Context mContext;
+
+        SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
+            mAudioManager = audioManager;
+            mHandler = handler;
+            mContext = context;
+        }
+
+        private int ringerModeToIndex(int ringerMode) {
+            // They just happen to coincide
+            return ringerMode;
+        }
+
+        private int indexToRingerMode(int index) {
+            // They just happen to coincide
+            return index;
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return null;
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
+
+            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
+            for (int i = 0; i < 3; i++) {
+                View itemView = v.findViewById(ITEM_IDS[i]);
+                itemView.setSelected(selectedIndex == i);
+                // Set up click handler
+                itemView.setTag(i);
+                itemView.setOnClickListener(this);
+            }
+            return v;
+        }
+
+        public void onPress() {
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        void willCreate() {
+        }
+
+        public void onClick(View v) {
+            if (!(v.getTag() instanceof Integer)) return;
+
+            int index = (Integer) v.getTag();
+            mAudioManager.setRingerMode(indexToRingerMode(index));
+            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+        }
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
+                if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
+                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
+                }
+            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+                // Airplane mode can be changed after ECM exits if airplane toggle button
+                // is pressed during ECM mode
+                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
+                        mIsWaitingForEcmExit) {
+                    mIsWaitingForEcmExit = false;
+                    changeAirplaneModeSystemSetting(true);
+                }
+            }
+        }
+    };
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            if (!mHasTelephony) return;
+            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
+            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
+            mAirplaneModeOn.updateState(mAirplaneState);
+            mAdapter.notifyDataSetChanged();
+        }
+    };
+
+    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
+            }
+        }
+    };
+
+    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            onAirplaneModeChanged();
+        }
+    };
+
+    private static final int MESSAGE_DISMISS = 0;
+    private static final int MESSAGE_REFRESH = 1;
+    private static final int MESSAGE_SHOW = 2;
+    private static final int DIALOG_DISMISS_DELAY = 300; // ms
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MESSAGE_DISMISS:
+                if (mDialog != null) {
+                    mDialog.dismiss();
+                    mDialog = null;
+                }
+                break;
+            case MESSAGE_REFRESH:
+                refreshSilentMode();
+                mAdapter.notifyDataSetChanged();
+                break;
+            case MESSAGE_SHOW:
+                handleShow();
+                break;
+            }
+        }
+    };
+
+    private void onAirplaneModeChanged() {
+        // Let the service state callbacks handle the state.
+        if (mHasTelephony) return;
+
+        boolean airplaneModeOn = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                0) == 1;
+        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
+        mAirplaneModeOn.updateState(mAirplaneState);
+    }
+
+    /**
+     * Change the airplane mode system setting
+     */
+    private void changeAirplaneModeSystemSetting(boolean on) {
+        Settings.Global.putInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                on ? 1 : 0);
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.putExtra("state", on);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        if (!mHasTelephony) {
+            mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
+        }
+    }
+
+    private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
+        private final Context mContext;
+        private final AlertController mAlert;
+        private final MyAdapter mAdapter;
+
+        public GlobalActionsDialog(Context context, AlertParams params) {
+            super(context, getDialogTheme(context));
+            mContext = getContext();
+            mAlert = AlertController.create(mContext, this, getWindow());
+            mAdapter = (MyAdapter) params.mAdapter;
+            params.apply(mAlert);
+        }
+
+        private static int getDialogTheme(Context context) {
+            TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+                    outValue, true);
+            return outValue.resourceId;
+        }
+
+        @Override
+        protected void onStart() {
+            super.setCanceledOnTouchOutside(true);
+            super.onStart();
+        }
+
+        public ListView getListView() {
+            return mAlert.getListView();
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mAlert.installContent();
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                for (int i = 0; i < mAdapter.getCount(); ++i) {
+                    CharSequence label =
+                            mAdapter.getItem(i).getLabelForAccessibility(getContext());
+                    if (label != null) {
+                        event.getText().add(label);
+                    }
+                }
+            }
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyDown(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyUp(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyUp(keyCode, event);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index b4467af..135b20d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -76,4 +76,26 @@
     void toggleRecentApps();
 
     void setCurrentUser(int newUserId);
+
+    void setGlobalActionsListener(GlobalActionsListener listener);
+    void showGlobalActions();
+
+    public interface GlobalActionsListener {
+        /**
+         * Called when sysui starts and connects its status bar, or when the status bar binder
+         * dies indicating sysui is no longer alive.
+         */
+        void onStatusBarConnectedChanged(boolean connected);
+
+        /**
+         * Callback from sysui to notify system that global actions has been successfully shown.
+         */
+        void onGlobalActionsShown();
+
+        /**
+         * Callback from sysui to notify system that the user has dismissed global actions and
+         * it no longer needs to be displayed (even if sysui dies).
+         */
+        void onGlobalActionsDismissed();
+    }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 2dfe20a8..aaaa080 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -40,6 +41,8 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationDelegate;
+import com.android.server.power.ShutdownThread;
+import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -65,6 +68,7 @@
 
     // for disabling the status bar
     private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    private GlobalActionsListener mGlobalActionListener;
     private IBinder mSysUiVisToken = new Binder();
     private int mDisabled1 = 0;
     private int mDisabled2 = 0;
@@ -307,6 +311,21 @@
                 } catch (RemoteException ex) {}
             }
         }
+
+        @Override
+        public void setGlobalActionsListener(GlobalActionsListener listener) {
+            mGlobalActionListener = listener;
+            mGlobalActionListener.onStatusBarConnectedChanged(mBar != null);
+        }
+
+        @Override
+        public void showGlobalActions() {
+            if (mBar != null) {
+                try {
+                    mBar.showGlobalActionsMenu();
+                } catch (RemoteException ex) {}
+            }
+        }
     };
 
     // ================================================================================
@@ -656,6 +675,17 @@
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
         mBar = bar;
+        try {
+            mBar.asBinder().linkToDeath(new DeathRecipient() {
+                @Override
+                public void binderDied() {
+                    mBar = null;
+                    notifyBarAttachChanged();
+                }
+            }, 0);
+        } catch (RemoteException e) {
+        }
+        notifyBarAttachChanged();
         synchronized (mIcons) {
             for (String slot : mIcons.keySet()) {
                 iconSlots.add(slot);
@@ -678,6 +708,13 @@
         }
     }
 
+    private void notifyBarAttachChanged() {
+        mHandler.post(() -> {
+            if (mGlobalActionListener == null) return;
+            mGlobalActionListener.onStatusBarConnectedChanged(mBar != null);
+        });
+    }
+
     /**
      * @param clearNotificationEffects whether to consider notifications as "shown" and stop
      *     LED, vibration, and ringing
@@ -715,6 +752,65 @@
         }
     }
 
+    /**
+     * Allows the status bar to shutdown the device.
+     */
+    @Override
+    public void shutdown() {
+        enforceStatusBarService();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mHandler.post(() ->
+                    ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false));
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Allows the status bar to reboot the device.
+     */
+    @Override
+    public void reboot(boolean safeMode) {
+        enforceStatusBarService();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mHandler.post(() -> {
+                if (safeMode) {
+                    ShutdownThread.rebootSafeMode(mContext, false);
+                } else {
+                    ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false);
+                }
+            });
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void onGlobalActionsShown() {
+        enforceStatusBarService();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (mGlobalActionListener == null) return;
+            mGlobalActionListener.onGlobalActionsShown();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void onGlobalActionsHidden() {
+        enforceStatusBarService();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (mGlobalActionListener == null) return;
+            mGlobalActionListener.onGlobalActionsDismissed();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public void onNotificationClick(String key) {
         enforceStatusBarService();
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index bd38be4..ef3d87c 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -35,7 +35,6 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Trace;
 import android.util.Slog;
 import android.view.IApplicationToken;
@@ -228,7 +227,7 @@
             boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
             int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
             boolean alwaysFocusable, AppWindowContainerController controller) {
-        return  new AppWindowToken(service, token, voiceInteraction, dc,
+        return new AppWindowToken(service, token, voiceInteraction, dc,
                 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
                 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
                 controller);
@@ -298,6 +297,17 @@
         }
     }
 
+    public void setDisablePreviewScreenshots(boolean disable) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
+                        + " token: " + mToken);
+                return;
+            }
+            mContainer.setDisablePreviewSnapshots(disable);
+        }
+    }
+
     public void setVisibility(boolean visible) {
         synchronized(mWindowMap) {
             if (mContainer == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ad73f46..111fbd3f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -167,6 +167,8 @@
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
+    private boolean mDisbalePreviewScreenshots;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -1433,6 +1435,14 @@
         return candidate;
     }
 
+    void setDisablePreviewSnapshots(boolean disable) {
+        mDisbalePreviewScreenshots = disable;
+    }
+
+    boolean shouldDisablePreviewScreenshots() {
+        return mDisbalePreviewScreenshots;
+    }
+
     @Override
     int getAnimLayerAdjustment() {
         return mAppAnimator.animLayerAdjustment;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 469a8a7..b8d0b8c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,11 +17,16 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
+import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
+import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_RARELY;
+import static android.graphics.PixelFormat.RGBA_8888;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
 import android.os.Environment;
 import android.util.ArraySet;
@@ -48,6 +53,26 @@
  */
 class TaskSnapshotController {
 
+    /**
+     * Return value for {@link #getSnapshotMode}: We are allowed to take a real screenshot to be
+     * used as the snapshot.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_REAL = 0;
+
+    /**
+     * Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but
+     * we should try to use the app theme to create a dummy representation of the app.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_APP_THEME = 1;
+
+    /**
+     * Return value for {@link #getSnapshotMode}: We aren't allowed to take any snapshot.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_NONE = 2;
+
     private final WindowManagerService mService;
 
     private final TaskSnapshotCache mCache;
@@ -88,10 +113,21 @@
         getClosingTasks(closingApps, mTmpTasks);
         for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
             final Task task = mTmpTasks.valueAt(i);
-            if (!canSnapshotTask(task)) {
-                continue;
+            final int mode = getSnapshotMode(task);
+            final TaskSnapshot snapshot;
+            switch (mode) {
+                case SNAPSHOT_MODE_NONE:
+                    continue;
+                case SNAPSHOT_MODE_APP_THEME:
+                    snapshot = drawAppThemeSnapshot(task);
+                    break;
+                case SNAPSHOT_MODE_REAL:
+                    snapshot = snapshotTask(task);
+                    break;
+                default:
+                    snapshot = null;
+                    break;
             }
-            final TaskSnapshot snapshot = snapshotTask(task);
             if (snapshot != null) {
                 mCache.putSnapshot(task, snapshot);
                 mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
@@ -152,8 +188,43 @@
         }
     }
 
-    private boolean canSnapshotTask(Task task) {
-        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
+    @VisibleForTesting
+    int getSnapshotMode(Task task) {
+        final AppWindowToken topChild = task.getTopChild();
+        if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
+            return SNAPSHOT_MODE_NONE;
+        } else if (topChild != null && topChild.shouldDisablePreviewScreenshots()) {
+            return SNAPSHOT_MODE_APP_THEME;
+        } else {
+            return SNAPSHOT_MODE_REAL;
+        }
+    }
+
+    /**
+     * If we are not allowed to take a real screenshot, this attempts to represent the app as best
+     * as possible by using the theme's window background.
+     */
+    private TaskSnapshot drawAppThemeSnapshot(Task task) {
+        final AppWindowToken topChild = task.getTopChild();
+        if (topChild == null) {
+            return null;
+        }
+        final WindowState mainWindow = topChild.findMainWindow();
+        if (mainWindow == null) {
+            return null;
+        }
+        final int color = task.getTaskDescription().getBackgroundColor();
+        final GraphicBuffer buffer = GraphicBuffer.create(mainWindow.getFrameLw().width(),
+                mainWindow.getFrameLw().height(),
+                RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_RARELY | USAGE_SW_READ_NEVER);
+        if (buffer == null) {
+            return null;
+        }
+        final Canvas c = buffer.lockCanvas();
+        c.drawColor(color);
+        buffer.unlockCanvasAndPost(c);
+        return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
+                mainWindow.mStableInsets, false /* reduced */, 1.0f /* scale */);
     }
 
     /**
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b77000b..9ed7c93 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -56,7 +56,7 @@
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
-import com.android.internal.policy.EmergencyAffordanceManager;
+import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
diff --git a/services/tests/notification/AndroidTest.xml b/services/tests/notification/AndroidTest.xml
new file mode 100644
index 0000000..46fdccc
--- /dev/null
+++ b/services/tests/notification/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Notification Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksNotificationTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksNotificationTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.frameworks.tests.notification" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index af44264..40af2f8 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -727,6 +727,11 @@
     }
 
     @Test
+    public void testDeleteNonExistentChannel() throws Exception {
+        mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
+    }
+
+    @Test
     public void testGetDeletedChannel() throws Exception {
         NotificationChannel channel =
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
new file mode 100644
index 0000000..4622d50
--- /dev/null
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Services Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksServicesTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksServicesTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.frameworks.servicestests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
index a2a4019..9343449 100644
--- a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
@@ -53,20 +53,22 @@
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.ArrayList;
 
 
 public class BaseLockSettingsServiceTests extends AndroidTestCase {
     protected static final int PRIMARY_USER_ID = 0;
     protected static final int MANAGED_PROFILE_USER_ID = 12;
+    protected static final int TURNED_OFF_PROFILE_USER_ID = 17;
     protected static final int SECONDARY_USER_ID = 20;
 
     private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER_ID, null, null,
             UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
-    private static final UserInfo MANAGED_PROFILE_INFO = new UserInfo(MANAGED_PROFILE_USER_ID, null,
-            null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
     private static final UserInfo SECONDARY_USER_INFO = new UserInfo(SECONDARY_USER_ID, null, null,
             UserInfo.FLAG_INITIALIZED);
 
+    private ArrayList<UserInfo> mPrimaryUserProfiles = new ArrayList<>();
+
     LockSettingsService mService;
 
     MockLockSettingsContext mContext;
@@ -106,13 +108,12 @@
         mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils,
                 mStorage, mGateKeeperService, mKeyStore, mStorageManager, mActivityManager);
         when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
-        when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(Arrays.asList(
-                new UserInfo[] {PRIMARY_USER_INFO, MANAGED_PROFILE_INFO}));
-        when(mUserManager.getUserInfo(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
-                MANAGED_PROFILE_INFO);
-        when(mUserManager.getProfileParent(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
-                PRIMARY_USER_INFO);
+        mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
+        installChildProfile(MANAGED_PROFILE_USER_ID);
+        installQuietModeChildProfile(TURNED_OFF_PROFILE_USER_ID);
+        when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserProfiles);
         when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO);
+        when(mUserManager.isUserRunning(eq(MANAGED_PROFILE_USER_ID))).thenReturn(true);
 
         when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer(
                 new Answer<Boolean>() {
@@ -132,6 +133,21 @@
                 new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
     }
 
+    private UserInfo installChildProfile(int profileId) {
+        final UserInfo userInfo = new UserInfo(
+            profileId, null, null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
+        mPrimaryUserProfiles.add(userInfo);
+        when(mUserManager.getUserInfo(eq(profileId))).thenReturn(userInfo);
+        when(mUserManager.getProfileParent(eq(profileId))).thenReturn(PRIMARY_USER_INFO);
+        return userInfo;
+    }
+
+    private UserInfo installQuietModeChildProfile(int profileId) {
+        final UserInfo userInfo = installChildProfile(profileId);
+        userInfo.flags |= UserInfo.FLAG_QUIET_MODE;
+        return userInfo;
+    }
+
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
index ae9762a..cfc3962 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsServiceTests.java
@@ -98,12 +98,18 @@
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
+        final long turnedOffprofileSid =
+                mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID);
         assertTrue(primarySid != 0);
         assertTrue(profileSid != 0);
         assertTrue(profileSid != primarySid);
+        assertTrue(turnedOffprofileSid != 0);
+        assertTrue(turnedOffprofileSid != primarySid);
+        assertTrue(turnedOffprofileSid != profileSid);
 
         // clear auth token and wait for verify challenge from primary user to re-generate it.
         mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
+        mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
         // verify credential
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
@@ -113,6 +119,9 @@
         assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
 
+        // Verify that profile which arent't running (e.g. turn off work) don't get unlocked
+        assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
+
         /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
          * credential as part of verifyCredential() before the new credential is committed in
          * StorageManager. So we relax the check in our mock StorageManager to allow that.
@@ -123,12 +132,14 @@
                 UnifiedPassword, PRIMARY_USER_ID);
         mStorageManager.setIgnoreBadUnlock(false);
         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+        assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
 
-        //Clear unified challenge
+        // Clear unified challenge
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, UnifiedPassword,
                 PRIMARY_USER_ID);
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
+        assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
     }
 
     public void testManagedProfileSeparateChallenge() throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 58d277b..2752340 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -18,7 +18,10 @@
 
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.TaskSnapshotController.*;
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
@@ -68,4 +71,17 @@
         sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
         assertEquals(0, closingTasks.size());
     }
+
+    @Test
+    public void testGetSnapshotMode() throws Exception {
+        final WindowState disabledWindow = createWindow(null,
+                FIRST_APPLICATION_WINDOW, sDisplayContent, "disabledWindow");
+        disabledWindow.mAppToken.setDisablePreviewSnapshots(true);
+        assertEquals(SNAPSHOT_MODE_APP_THEME,
+                sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
+        final WindowState normalWindow = createWindow(null,
+                FIRST_APPLICATION_WINDOW, sDisplayContent, "normalWindow");
+        assertEquals(SNAPSHOT_MODE_REAL,
+                sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index ce632ae..6f78245 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -42,6 +42,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.EMPTY;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 7b9c9f1..64cdcf7 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -79,5 +79,13 @@
             android:singleUser="true" android:exported="true" />
         <receiver android:name="TrackTimeReceiver" />
         <receiver android:name="AlarmSpamReceiver" />
+        <activity android:name="DisableScreenshotsActivity"
+                android:label="DisableScreenshots"
+                android:theme="@style/DisableScreenshots">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/ActivityTests/res/values/colors.xml b/tests/ActivityTests/res/values/colors.xml
new file mode 100644
index 0000000..9925722
--- /dev/null
+++ b/tests/ActivityTests/res/values/colors.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <color name="blue">#0000ff</color>
+</resources>
\ No newline at end of file
diff --git a/tests/ActivityTests/res/values/themes.xml b/tests/ActivityTests/res/values/themes.xml
index 67f5938..b8dd830 100644
--- a/tests/ActivityTests/res/values/themes.xml
+++ b/tests/ActivityTests/res/values/themes.xml
@@ -22,4 +22,8 @@
         <item name="android:windowEnterAnimation">@anim/slow_enter</item>
         <item name="android:windowExitAnimation">@anim/slow_exit</item>
     </style>
+    <style name="DisableScreenshots" parent="@android:style/Theme.Material">
+        <item name="android:colorBackground">@color/blue</item>
+        <item name="android:windowBackground">@color/blue</item>
+    </style>
 </resources>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
new file mode 100644
index 0000000..fa5724e
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.google.android.test.activity;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.SystemClock;
+
+/**
+ * Activity for which screenshotting is disabled.
+ */
+public class DisableScreenshotsActivity extends Activity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setDisablePreviewScreenshots(true);
+        getWindow().getDecorView().setBackgroundColor(Color.RED);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // This is to simulate slowness over resuming the app, such that we have plenty of time to
+        // see the starting window.
+        SystemClock.sleep(500);
+    }
+}
diff --git a/tests/TouchLatency/Android.mk b/tests/TouchLatency/Android.mk
index 73b5b6c..6ad4705 100644
--- a/tests/TouchLatency/Android.mk
+++ b/tests/TouchLatency/Android.mk
@@ -24,4 +24,6 @@
 
 LOCAL_PACKAGE_NAME := TouchLatency
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_PACKAGE)
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index be9a541..36ebc90 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -33,4 +33,6 @@
 
 LOCAL_PACKAGE_NAME := UiBench
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_PACKAGE)
diff --git a/tests/net/AndroidTest.xml b/tests/net/AndroidTest.xml
new file mode 100644
index 0000000..6c0a6d0
--- /dev/null
+++ b/tests/net/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Networking Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksNetTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksNetTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="com.android.frameworks.tests.net" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 60f0d56..391aa47 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4765,6 +4765,7 @@
     const String16 vector16("vector");
     const String16 animatedVector16("animated-vector");
     const String16 pathInterpolator16("pathInterpolator");
+    const String16 objectAnimator16("objectAnimator");
 
     const int minSdk = getMinSdkVersion(bundle);
     if (minSdk >= SDK_LOLLIPOP_MR1) {
@@ -4791,6 +4792,7 @@
 
         if (bundle->getNoVersionVectors() && (node->getElementName() == vector16 ||
                     node->getElementName() == animatedVector16 ||
+                    node->getElementName() == objectAnimator16 ||
                     node->getElementName() == pathInterpolator16)) {
             // We were told not to version vector tags, so skip the children here.
             continue;
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
new file mode 100644
index 0000000..c30dcea
--- /dev/null
+++ b/wifi/tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Wifi API Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksWifiApiTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksWifiApiTests" />
+    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+        <option name="package" value="android.net.wifi.test" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>