Merge "Removing per-user PiP component."
diff --git a/Android.mk b/Android.mk
index b46aeb8..e324a75 100644
--- a/Android.mk
+++ b/Android.mk
@@ -282,6 +282,7 @@
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
 	core/java/android/service/notification/IConditionProvider.aidl \
+	core/java/android/service/vr/IPersistentVrStateCallbacks.aidl \
 	core/java/android/service/vr/IVrListener.aidl \
 	core/java/android/service/vr/IVrManager.aidl \
 	core/java/android/service/vr/IVrStateCallbacks.aidl \
@@ -570,6 +571,9 @@
     android.hardware.usb@1.0-java-constants             \
     android.hardware.vibrator@1.0-java-constants        \
 
+# Loaded with System.loadLibrary by android.view.textclassifier
+LOCAL_REQUIRED_MODULES += libtextclassifier
+
 LOCAL_PROTOC_OPTIMIZE_TYPE := stream
 LOCAL_PROTOC_FLAGS := \
     -Iexternal/protobuf/src
@@ -989,11 +993,13 @@
 
 framework_docs_LOCAL_DROIDDOC_OPTIONS += \
 		-hdf dac true \
-		-hdf sdk.codename N \
-		-hdf sdk.preview.version 5 \
+		-hdf sdk.codename O \
+		-hdf sdk.preview.version 1 \
 		-hdf sdk.version $(framework_docs_SDK_VERSION) \
 		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-		-hdf sdk.preview 0
+		-hdf sdk.preview 0 \
+		-resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
+		-resourcesoutdir reference/android/images/
 
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
@@ -1190,9 +1196,7 @@
 		-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
 		-sdkvalues $(OUT_DOCS) \
 		-hdf android.whichdoc offline \
-		-referenceonly \
-		-resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
-		-resourcesoutdir reference/android/images/
+		-referenceonly
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
 
diff --git a/api/current.txt b/api/current.txt
index 235a4a6..33eb074 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -608,6 +608,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int fontProviderAuthority = 16844114; // 0x1010552
+    field public static final int fontProviderCerts = 16844128; // 0x1010560
     field public static final int fontProviderPackage = 16844122; // 0x101055a
     field public static final int fontProviderQuery = 16844115; // 0x1010553
     field public static final int fontStyle = 16844095; // 0x101053f
@@ -695,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
@@ -1179,6 +1182,7 @@
     field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
     field public static final int shrinkColumns = 16843082; // 0x101014a
     field public static final deprecated int singleLine = 16843101; // 0x101015d
+    field public static final int singleLineTitle = 16844127; // 0x101055f
     field public static final int singleUser = 16843711; // 0x10103bf
     field public static final int slideEdge = 16843824; // 0x1010430
     field public static final int smallIcon = 16843422; // 0x101029e
@@ -4844,6 +4848,7 @@
 
   public class Instrumentation {
     ctor public Instrumentation();
+    method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
@@ -5504,6 +5509,7 @@
     method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
+    method public java.lang.String getDescription();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
@@ -5513,6 +5519,7 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
+    method public void setDescription(java.lang.String);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
     method public void setLightColor(int);
@@ -9483,7 +9490,7 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
-    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
@@ -10625,6 +10632,7 @@
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
+    field public static final java.lang.String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
@@ -13763,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);
@@ -31560,6 +31588,16 @@
     method public static long uptimeMillis();
   }
 
+  public class TestLooperManager {
+    method public void execute(android.os.Message);
+    method public android.os.MessageQueue getQueue();
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, int);
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, java.lang.Runnable);
+    method public android.os.Message next();
+    method public void recycle(android.os.Message);
+    method public void release();
+  }
+
   public abstract class TokenWatcher {
     ctor public TokenWatcher(android.os.Handler, java.lang.String);
     method public void acquire(android.os.IBinder, java.lang.String);
@@ -32017,6 +32055,7 @@
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
+    method public boolean isSingleLineTitle();
     method protected void notifyChanged();
     method public void notifyDependencyChange(boolean);
     method protected void notifyHierarchyChanged();
@@ -32058,6 +32097,7 @@
     method public void setRecycleEnabled(boolean);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
+    method public void setSingleLineTitle(boolean);
     method public void setSummary(java.lang.CharSequence);
     method public void setSummary(int);
     method public void setTitle(java.lang.CharSequence);
@@ -36854,9 +36894,11 @@
 
   public static final class Dataset.Builder {
     ctor public Dataset.Builder(android.widget.RemoteViews);
+    ctor public Dataset.Builder();
     method public android.service.autofill.Dataset build();
     method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
+    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
   }
 
   public final class FillCallback {
@@ -41007,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();
@@ -44575,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();
@@ -44602,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);
@@ -46324,7 +46371,6 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46333,11 +46379,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHint(java.lang.String[]);
+    method public abstract void setAutofillId(android.view.ViewStructure, int);
     method public abstract void setAutofillOptions(java.lang.String[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
diff --git a/api/system-current.txt b/api/system-current.txt
index abdcaaa..60d7f2f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -721,6 +721,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int fontProviderAuthority = 16844114; // 0x1010552
+    field public static final int fontProviderCerts = 16844128; // 0x1010560
     field public static final int fontProviderPackage = 16844122; // 0x101055a
     field public static final int fontProviderQuery = 16844115; // 0x1010553
     field public static final int fontStyle = 16844095; // 0x101053f
@@ -808,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
@@ -1296,6 +1299,7 @@
     field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
     field public static final int shrinkColumns = 16843082; // 0x101014a
     field public static final deprecated int singleLine = 16843101; // 0x101015d
+    field public static final int singleLineTitle = 16844127; // 0x101055f
     field public static final int singleUser = 16843711; // 0x10103bf
     field public static final int slideEdge = 16843824; // 0x1010430
     field public static final int smallIcon = 16843422; // 0x101029e
@@ -3859,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);
@@ -5013,6 +5018,7 @@
 
   public class Instrumentation {
     ctor public Instrumentation();
+    method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
@@ -5689,6 +5695,7 @@
     method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
+    method public java.lang.String getDescription();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
@@ -5701,6 +5708,7 @@
     method public boolean isDeleted();
     method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
     method public void setBypassDnd(boolean);
+    method public void setDescription(java.lang.String);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
     method public void setLightColor(int);
@@ -5716,16 +5724,6 @@
     method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
     field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
-    field public static final int[] LOCKABLE_FIELDS;
-    field public static final int USER_LOCKED_ALLOWED = 64; // 0x40
-    field public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 256; // 0x100
-    field public static final int USER_LOCKED_IMPORTANCE = 4; // 0x4
-    field public static final int USER_LOCKED_LIGHTS = 8; // 0x8
-    field public static final int USER_LOCKED_PRIORITY = 1; // 0x1
-    field public static final int USER_LOCKED_SHOW_BADGE = 128; // 0x80
-    field public static final int USER_LOCKED_SOUND = 32; // 0x20
-    field public static final int USER_LOCKED_VIBRATION = 16; // 0x10
-    field public static final int USER_LOCKED_VISIBILITY = 2; // 0x2
   }
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -10018,7 +10016,7 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
-    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
@@ -11281,6 +11279,7 @@
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
+    field public static final java.lang.String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
@@ -14496,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);
@@ -34321,6 +34340,16 @@
     method public static long uptimeMillis();
   }
 
+  public class TestLooperManager {
+    method public void execute(android.os.Message);
+    method public android.os.MessageQueue getQueue();
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, int);
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, java.lang.Runnable);
+    method public android.os.Message next();
+    method public void recycle(android.os.Message);
+    method public void release();
+  }
+
   public abstract class TokenWatcher {
     ctor public TokenWatcher(android.os.Handler, java.lang.String);
     method public void acquire(android.os.IBinder, java.lang.String);
@@ -34867,6 +34896,7 @@
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
+    method public boolean isSingleLineTitle();
     method protected void notifyChanged();
     method public void notifyDependencyChange(boolean);
     method protected void notifyHierarchyChanged();
@@ -34908,6 +34938,7 @@
     method public void setRecycleEnabled(boolean);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
+    method public void setSingleLineTitle(boolean);
     method public void setSummary(java.lang.CharSequence);
     method public void setSummary(int);
     method public void setTitle(java.lang.CharSequence);
@@ -39888,9 +39919,11 @@
 
   public static final class Dataset.Builder {
     ctor public Dataset.Builder(android.widget.RemoteViews);
+    ctor public Dataset.Builder();
     method public android.service.autofill.Dataset build();
     method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
+    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
   }
 
   public final class FillCallback {
@@ -44469,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();
@@ -48038,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();
@@ -48065,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);
@@ -49787,7 +49825,6 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -49796,11 +49833,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHint(java.lang.String[]);
+    method public abstract void setAutofillId(android.view.ViewStructure, int);
     method public abstract void setAutofillOptions(java.lang.String[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
diff --git a/api/test-current.txt b/api/test-current.txt
index 3fb42a4..39663f2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -608,6 +608,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int fontProviderAuthority = 16844114; // 0x1010552
+    field public static final int fontProviderCerts = 16844128; // 0x1010560
     field public static final int fontProviderPackage = 16844122; // 0x101055a
     field public static final int fontProviderQuery = 16844115; // 0x1010553
     field public static final int fontStyle = 16844095; // 0x101053f
@@ -695,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
@@ -1179,6 +1182,7 @@
     field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
     field public static final int shrinkColumns = 16843082; // 0x101014a
     field public static final deprecated int singleLine = 16843101; // 0x101015d
+    field public static final int singleLineTitle = 16844127; // 0x101055f
     field public static final int singleUser = 16843711; // 0x10103bf
     field public static final int slideEdge = 16843824; // 0x1010430
     field public static final int smallIcon = 16843422; // 0x101029e
@@ -4854,6 +4858,7 @@
 
   public class Instrumentation {
     ctor public Instrumentation();
+    method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
@@ -5514,6 +5519,7 @@
     method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
+    method public java.lang.String getDescription();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
@@ -5523,6 +5529,7 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
+    method public void setDescription(java.lang.String);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
     method public void setLightColor(int);
@@ -9513,7 +9520,7 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
-    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
@@ -10661,6 +10668,7 @@
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
+    field public static final java.lang.String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
@@ -13801,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);
@@ -31683,6 +31711,16 @@
     method public static long uptimeMillis();
   }
 
+  public class TestLooperManager {
+    method public void execute(android.os.Message);
+    method public android.os.MessageQueue getQueue();
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, int);
+    method public boolean hasMessages(android.os.Handler, java.lang.Object, java.lang.Runnable);
+    method public android.os.Message next();
+    method public void recycle(android.os.Message);
+    method public void release();
+  }
+
   public abstract class TokenWatcher {
     ctor public TokenWatcher(android.os.Handler, java.lang.String);
     method public void acquire(android.os.IBinder, java.lang.String);
@@ -32142,6 +32180,7 @@
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
+    method public boolean isSingleLineTitle();
     method protected void notifyChanged();
     method public void notifyDependencyChange(boolean);
     method protected void notifyHierarchyChanged();
@@ -32183,6 +32222,7 @@
     method public void setRecycleEnabled(boolean);
     method public void setSelectable(boolean);
     method public void setShouldDisableView(boolean);
+    method public void setSingleLineTitle(boolean);
     method public void setSummary(java.lang.CharSequence);
     method public void setSummary(int);
     method public void setTitle(java.lang.CharSequence);
@@ -37000,9 +37040,11 @@
 
   public static final class Dataset.Builder {
     ctor public Dataset.Builder(android.widget.RemoteViews);
+    ctor public Dataset.Builder();
     method public android.service.autofill.Dataset build();
     method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
+    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
   }
 
   public final class FillCallback {
@@ -41202,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();
@@ -44935,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();
@@ -44962,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);
@@ -46693,7 +46740,6 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46702,11 +46748,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHint(java.lang.String[]);
+    method public abstract void setAutofillId(android.view.ViewStructure, int);
     method public abstract void setAutofillOptions(java.lang.String[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 75d4f32..6d4b812 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -344,6 +344,17 @@
         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
 
     /**
+     * Action sent as a broadcast Intent to specific package by the AccountsService
+     * when account visibility or account's credentials (saved password, etc) are changed.
+     *
+     * @see #addOnAccountsUpdatedListener
+     *
+     * @hide
+     */
+    public static final String ACTION_VISIBLE_ACCOUNTS_CHANGED =
+        "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
+
+    /**
      * Key to set default visibility for applications targeting API level
      * {@link android.os.Build.VERSION_CODES#O} or above and don't have the same signature as
      * authenticator See {@link #getAccountVisibility}. If the value was not set by authenticator
@@ -1057,8 +1068,8 @@
 
     /**
      * Gets the previous name associated with the account or {@code null}, if
-     * none. This is intended so that clients of {@link
-     * #LOGIN_ACCOUNTS_CHANGED_ACTION} broadcasts can determine if an
+     * none. This is intended so that clients of
+     * {@link OnAccountsUpdateListener} can determine if an
      * authenticator has renamed an account.
      *
      * <p>It is safe to call this method from the main thread.
@@ -1555,7 +1566,8 @@
      * <p>In that case, you may need to wait until the user responds, which
      * could take hours or days or forever.  When the user does respond and
      * supply a new password, the account manager will broadcast the
-     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
+     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent and
+     * notify {@link OnAccountsUpdateListener} which applications can
      * use to try again.
      *
      * <p>If notifyAuthFailure is not set, it is the application's
@@ -1631,7 +1643,8 @@
      * <p>In that case, you may need to wait until the user responds, which
      * could take hours or days or forever.  When the user does respond and
      * supply a new password, the account manager will broadcast the
-     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
+     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent and
+     * notify {@link OnAccountsUpdateListener} which applications can
      * use to try again.
      *
      * <p>If notifyAuthFailure is not set, it is the application's
@@ -2811,7 +2824,7 @@
             Maps.newHashMap();
 
     /**
-     * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
+     * BroadcastReceiver that listens for the ACTION_VISIBLE_ACCOUNTS_CHANGED intent
      * so that it can read the updated list of accounts and send them to the listener
      * in mAccountsUpdatedListeners.
      */
@@ -2881,22 +2894,27 @@
             mAccountsUpdatedListeners.put(listener, handler);
             if (accountTypes != null) {
                 mAccountsUpdatedListenersTypes.put(listener,
-                        new HashSet<String>(Arrays.asList(accountTypes)));
+                    new HashSet<String>(Arrays.asList(accountTypes)));
+            } else {
+                mAccountsUpdatedListenersTypes.put(listener, null);
             }
 
             if (wasEmpty) {
                 // Register a broadcast receiver to monitor account changes
                 IntentFilter intentFilter = new IntentFilter();
-                // TODO get rid of the broadcast receiver
-                // create android.os.ResultReceiver
-                // send it to the service via aidl
-                // handle onReceiveResult
-                intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
+                intentFilter.addAction(ACTION_VISIBLE_ACCOUNTS_CHANGED);
                 // To recover from disk-full.
                 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
-                // Register a broadcast receiver to monitor account changes
                 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
             }
+
+            try {
+                // Notify AccountManagedService about new receiver.
+                // The receiver must be unregistered later exactly one time
+                mService.registerAccountListener(accountTypes, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
         if (updateImmediately) {
             postToHandler(handler, listener, getAccounts());
@@ -2923,11 +2941,23 @@
                 Log.e(TAG, "Listener was not previously added");
                 return;
             }
+            Set<String> accountTypes = mAccountsUpdatedListenersTypes.get(listener);
+            String[] accountsArray;
+            if (accountTypes != null) {
+                accountsArray = accountTypes.toArray(new String[accountTypes.size()]);
+            } else {
+                accountsArray = null;
+            }
             mAccountsUpdatedListeners.remove(listener);
             mAccountsUpdatedListenersTypes.remove(listener);
             if (mAccountsUpdatedListeners.isEmpty()) {
                 mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
             }
+            try {
+                mService.unregisterAccountListener(accountsArray, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
     }
 
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 49cd2c6..7494cfc 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -117,6 +117,9 @@
     /* Type may be null returns Map <Account, Integer>*/
     Map getAccountsAndVisibilityForPackage(in String packageName, in String accountType);
 
+    void registerAccountListener(in String[] accountTypes, String opPackageName);
+    void unregisterAccountListener(in String[] accountTypes, String opPackageName);
+
     /* Check if the package in a user can access an account */
     boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
     /* Crate an intent to request account access for package and a given user id */
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/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 55407e6..286f8570 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2139,11 +2139,12 @@
     @Override
     public void getPackageSizeInfoAsUser(String packageName, int userHandle,
             IPackageStatsObserver observer) {
+        final String msg = "Shame on you for calling the hidden API "
+                + "getPackageSizeInfoAsUser(). Shame!";
         if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
-            throw new UnsupportedOperationException(
-                    "Shame on you for calling a hidden API. Shame!");
+            throw new UnsupportedOperationException(msg);
         } else if (observer != null) {
-            Log.d(TAG, "Shame on you for calling a hidden API. Shame!");
+            Log.d(TAG, msg);
             try {
                 observer.onGetStatsCompleted(null, false);
             } catch (RemoteException ignored) {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index c88448a..f564e8d 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -370,7 +370,7 @@
 
     public BackStackRecord(FragmentManagerImpl manager) {
         mManager = manager;
-        mAllowOptimization = getTargetSdk() > Build.VERSION_CODES.N_MR1;
+        mAllowOptimization = mManager.getTargetSdk() > Build.VERSION_CODES.N_MR1;
     }
 
     public int getId() {
@@ -423,7 +423,7 @@
     }
 
     private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
-        if (getTargetSdk() > Build.VERSION_CODES.N_MR1) {
+        if (mManager.getTargetSdk() > Build.VERSION_CODES.N_MR1) {
             final Class fragmentClass = fragment.getClass();
             final int modifiers = fragmentClass.getModifiers();
             if ((fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
@@ -1022,22 +1022,4 @@
     public boolean isEmpty() {
         return mOps.isEmpty();
     }
-
-    /**
-     * @return the target SDK of the FragmentManager's application info. If the
-     * FragmentManager has been torn down, then 0 is returned.
-     */
-    private int getTargetSdk() {
-        FragmentHostCallback host = mManager.mHost;
-        if (host != null) {
-            Context context = host.getContext();
-            if (context != null) {
-                ApplicationInfo info = context.getApplicationInfo();
-                if (info != null) {
-                    return info.targetSdkVersion;
-                }
-            }
-        }
-        return 0;
-    }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8a3d9b1..4232617 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -63,6 +63,7 @@
 import android.os.ServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IStorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -365,6 +366,13 @@
     @Override
     public SharedPreferences getSharedPreferences(File file, int mode) {
         checkMode(mode);
+        if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
+            if (isCredentialProtectedStorage()
+                    && !getSystemService(UserManager.class).isUserUnlocked()) {
+                throw new IllegalStateException("SharedPreferences in credential encrypted "
+                        + "storage are not available until after user is unlocked");
+            }
+        }
         SharedPreferencesImpl sp;
         synchronized (ContextImpl.class) {
             final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0672e3b..0d859a1 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -23,9 +23,11 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Looper;
@@ -674,6 +676,10 @@
     // Postponed transactions.
     ArrayList<StartEnterTransitionListener> mPostponedTransactions;
 
+    // Prior to O, we allowed executing transactions during fragment manager state changes.
+    // This is dangerous, but we want to keep from breaking old applications.
+    boolean mAllowOldReentrantBehavior;
+
     Runnable mExecCommit = new Runnable() {
         @Override
         public void run() {
@@ -2815,69 +2821,92 @@
         mHost = host;
         mContainer = container;
         mParent = parent;
+        mAllowOldReentrantBehavior = getTargetSdk() <= Build.VERSION_CODES.N_MR1;
     }
-    
+
+    /**
+     * @return the target SDK of the FragmentManager's application info. If the
+     * FragmentManager has been torn down, then 0 is returned.
+     */
+    int getTargetSdk() {
+        if (mHost != null) {
+            Context context = mHost.getContext();
+            if (context != null) {
+                ApplicationInfo info = context.getApplicationInfo();
+                if (info != null) {
+                    return info.targetSdkVersion;
+                }
+            }
+        }
+        return 0;
+    }
+
     public void noteStateNotSaved() {
         mStateSaved = false;
     }
     
     public void dispatchCreate() {
         mStateSaved = false;
-        mExecutingActions = true;
-        moveToState(Fragment.CREATED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.CREATED);
     }
     
     public void dispatchActivityCreated() {
         mStateSaved = false;
-        mExecutingActions = true;
-        moveToState(Fragment.ACTIVITY_CREATED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.ACTIVITY_CREATED);
     }
     
     public void dispatchStart() {
         mStateSaved = false;
-        mExecutingActions = true;
-        moveToState(Fragment.STARTED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.STARTED);
     }
     
     public void dispatchResume() {
         mStateSaved = false;
-        mExecutingActions = true;
-        moveToState(Fragment.RESUMED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.RESUMED);
     }
     
     public void dispatchPause() {
-        mExecutingActions = true;
-        moveToState(Fragment.STARTED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.STARTED);
     }
     
     public void dispatchStop() {
-        mExecutingActions = true;
-        moveToState(Fragment.STOPPED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.STOPPED);
     }
     
     public void dispatchDestroyView() {
-        mExecutingActions = true;
-        moveToState(Fragment.CREATED, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.CREATED);
     }
 
     public void dispatchDestroy() {
         mDestroyed = true;
         execPendingActions();
-        mExecutingActions = true;
-        moveToState(Fragment.INITIALIZING, false);
-        mExecutingActions = false;
+        dispatchMoveToState(Fragment.INITIALIZING);
         mHost = null;
         mContainer = null;
         mParent = null;
     }
 
+    /**
+     * This method is called by dispatch* methods to change the FragmentManager's state.
+     * It calls moveToState directly if the target SDK is older than O. Otherwise, it sets and
+     * clears mExecutingActions to ensure that there is no reentrancy while the
+     * FragmentManager is changing state.
+     *
+     * @param state The new state of the FragmentManager.
+     */
+    private void dispatchMoveToState(int state) {
+        if (mAllowOldReentrantBehavior) {
+            moveToState(state, false);
+        } else {
+            try {
+                mExecutingActions = true;
+                moveToState(state, false);
+            } finally {
+                mExecutingActions = false;
+            }
+        }
+    }
+
     public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
         if (mAdded == null) {
             return;
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/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4db29fb..f9a3ea7 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -37,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.TestLooperManager;
 import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
@@ -110,6 +111,22 @@
     }
 
     /**
+     * Called for methods that shouldn't be called by standard apps and
+     * should only be used in instrumentation environments. This is not
+     * security feature as these classes will still be accessible through
+     * reflection, but it will serve as noticeable discouragement from
+     * doing such a thing.
+     */
+    private void checkInstrumenting(String method) {
+        // Check if we have an instrumentation context, as init should only get called by
+        // the system in startup processes that are being instrumented.
+        if (mInstrContext == null) {
+            throw new RuntimeException(method +
+                    " cannot be called outside of instrumented processes");
+        }
+    }
+
+    /**
      * Called when the instrumentation is starting, before any application code
      * has been loaded.  Usually this will be implemented to simply call
      * {@link #start} to begin the instrumentation thread, which will then
@@ -2024,6 +2041,15 @@
         return null;
     }
 
+    /**
+     * Takes control of the execution of messages on the specified looper until
+     * {@link TestLooperManager#release} is called.
+     */
+    public TestLooperManager acquireLooperManager(Looper looper) {
+        checkInstrumenting("acquireLooperManager");
+        return new TestLooperManager(looper);
+    }
+
     private final class InstrumentationThread extends Thread {
         public InstrumentationThread(String name) {
             super(name);
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 29c4520..92216d1 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -20,9 +20,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.content.Intent;
 import android.media.AudioAttributes;
@@ -46,8 +43,15 @@
      */
     public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
 
+    /**
+     * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
+     * limit.
+     */
+    private static final int MAX_TEXT_LENGTH = 1000;
+
     private static final String TAG_CHANNEL = "channel";
     private static final String ATT_NAME = "name";
+    private static final String ATT_DESC = "desc";
     private static final String ATT_ID = "id";
     private static final String ATT_DELETED = "deleted";
     private static final String ATT_PRIORITY = "priority";
@@ -69,56 +73,46 @@
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_PRIORITY = 0x00000001;
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_VISIBILITY = 0x00000002;
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_IMPORTANCE = 0x00000004;
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_LIGHTS = 0x00000008;
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_VIBRATION = 0x00000010;
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_SOUND = 0x00000020;
 
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_ALLOWED = 0x00000040;
 
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
 
     /**
      * @hide
      */
-    @SystemApi
     public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 0x00000100;
 
     /**
      * @hide
      */
-    @SystemApi
     public static final int[] LOCKABLE_FIELDS = new int[] {
             USER_LOCKED_PRIORITY,
             USER_LOCKED_VISIBILITY,
@@ -140,7 +134,8 @@
     private static final boolean DEFAULT_SHOW_BADGE = true;
 
     private final String mId;
-    private CharSequence mName;
+    private String mName;
+    private String mDesc;
     private int mImportance = DEFAULT_IMPORTANCE;
     private boolean mBypassDnd;
     private int mLockscreenVisibility = DEFAULT_VISIBILITY;
@@ -158,19 +153,19 @@
     /**
      * Creates a notification channel.
      *
-     * @param id The id of the channel. Must be unique per package.
-     * @param name The user visible name of the channel. Unchangeable once created; use this
-     *             constructor if the channel represents a user-defined category that does not
-     *             need to be translated. You can rename this channel when the system
+     * @param id The id of the channel. Must be unique per package. The value may be truncated if
+     *           it is too long.
+     * @param name The user visible name of the channel. You can rename this channel when the system
      *             locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
-     *             broadcast.
+     *             broadcast. The recommended maximum length is 40 characters; the value may be
+     *             truncated if it is too long.
      * @param importance The importance of the channel. This controls how interruptive notifications
      *                   posted to this channel are. See e.g.
      *                   {@link NotificationManager#IMPORTANCE_DEFAULT}.
      */
     public NotificationChannel(String id, CharSequence name, int importance) {
-        this.mId = id;
-        this.mName = name;
+        this.mId = getTrimmedString(id);
+        this.mName = name != null ? getTrimmedString(name.toString()) : null;
         this.mImportance = importance;
     }
 
@@ -180,7 +175,16 @@
         } else {
             mId = null;
         }
-        mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        if (in.readByte() != 0) {
+            mName = in.readString();
+        } else {
+            mName = null;
+        }
+        if (in.readByte() != 0) {
+            mDesc = in.readString();
+        } else {
+            mDesc = null;
+        }
         mImportance = in.readInt();
         mBypassDnd = in.readByte() != 0;
         mLockscreenVisibility = in.readInt();
@@ -212,7 +216,18 @@
         } else {
             dest.writeByte((byte) 0);
         }
-        TextUtils.writeToParcel(mName, dest, flags);
+        if (mName != null) {
+            dest.writeByte((byte) 1);
+            dest.writeString(mName);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        if (mDesc != null) {
+            dest.writeByte((byte) 1);
+            dest.writeString(mDesc);
+        } else {
+            dest.writeByte((byte) 0);
+        }
         dest.writeInt(mImportance);
         dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
         dest.writeInt(mLockscreenVisibility);
@@ -257,46 +272,33 @@
         mDeleted = deleted;
     }
 
+    // Modifiable by apps post channel creation
+
     /**
-     * Sets the name of this channel.
+     * Sets the user visible name of this channel.
+     *
+     * <p>The recommended maximum length is 40 characters; the value may be truncated if it is too
+     * long.
      */
     public void setName(CharSequence name) {
-        mName = name;
-    }
-
-    // Modifiable by a notification ranker.
-
-    /**
-     * Sets whether or not notifications posted to this channel can interrupt the user in
-     * {@link android.app.NotificationManager.Policy#INTERRUPTION_FILTER_PRIORITY} mode.
-     *
-     * Only modifiable by the system and notification ranker.
-     */
-    public void setBypassDnd(boolean bypassDnd) {
-        this.mBypassDnd = bypassDnd;
+        mName = name != null ? getTrimmedString(name.toString()) : null;
     }
 
     /**
-     * Sets whether notifications posted to this channel appear on the lockscreen or not, and if so,
-     * whether they appear in a redacted form. See e.g. {@link Notification#VISIBILITY_SECRET}.
+     * Sets the user visible description of this channel.
      *
-     * Only modifiable by the system and notification ranker.
+     * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
+     * long.
      */
-    public void setLockscreenVisibility(int lockscreenVisibility) {
-        this.mLockscreenVisibility = lockscreenVisibility;
+    public void setDescription(String description) {
+        mDesc = getTrimmedString(description);
     }
 
-    /**
-     * Sets the level of interruption of this notification channel.
-     *
-     * Only modifiable by the system and notification ranker.
-     *
-     * @param importance the amount the user should be interrupted by notifications from this
-     *                   channel. See e.g.
-     *                   {@link android.app.NotificationManager#IMPORTANCE_DEFAULT}.
-     */
-    public void setImportance(int importance) {
-        this.mImportance = importance;
+    private String getTrimmedString(String input) {
+        if (input != null && input.length() > MAX_TEXT_LENGTH) {
+            return input.substring(0, MAX_TEXT_LENGTH);
+        }
+        return input;
     }
 
     // Modifiable by apps on channel creation.
@@ -385,6 +387,43 @@
     }
 
     /**
+     * Sets the level of interruption of this notification channel.
+     *
+     * Only modifiable before the channel is submitted to
+     * {@link NotificationManager#notify(String, int, Notification)}.
+     *
+     * @param importance the amount the user should be interrupted by notifications from this
+     *                   channel. See e.g.
+     *                   {@link android.app.NotificationManager#IMPORTANCE_DEFAULT}.
+     */
+    public void setImportance(int importance) {
+        this.mImportance = importance;
+    }
+
+    // Modifiable by a notification ranker.
+
+    /**
+     * Sets whether or not notifications posted to this channel can interrupt the user in
+     * {@link android.app.NotificationManager.Policy#INTERRUPTION_FILTER_PRIORITY} mode.
+     *
+     * Only modifiable by the system and notification ranker.
+     */
+    public void setBypassDnd(boolean bypassDnd) {
+        this.mBypassDnd = bypassDnd;
+    }
+
+    /**
+     * Sets whether notifications posted to this channel appear on the lockscreen or not, and if so,
+     * whether they appear in a redacted form. See e.g. {@link Notification#VISIBILITY_SECRET}.
+     *
+     * Only modifiable by the system and notification ranker.
+     */
+    public void setLockscreenVisibility(int lockscreenVisibility) {
+        this.mLockscreenVisibility = lockscreenVisibility;
+    }
+
+
+    /**
      * Returns the id of this channel.
      */
     public String getId() {
@@ -394,11 +433,18 @@
     /**
      * Returns the user visible name of this channel.
      */
-    public @Nullable CharSequence getName() {
+    public CharSequence getName() {
         return mName;
     }
 
     /**
+     * Returns the user visible description of this channel.
+     */
+    public String getDescription() {
+        return mDesc;
+    }
+
+    /**
      * Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
      * notifications posted to this channel.
      */
@@ -507,6 +553,7 @@
     @SystemApi
     public void populateFromXml(XmlPullParser parser) {
         // Name, id, and importance are set in the constructor.
+        setDescription(parser.getAttributeValue(null, ATT_DESC));
         setBypassDnd(Notification.PRIORITY_DEFAULT
                 != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
         setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
@@ -531,6 +578,9 @@
         if (getName() != null) {
             out.attribute(null, ATT_NAME, getName().toString());
         }
+        if (getDescription() != null) {
+            out.attribute(null, ATT_DESC, getDescription());
+        }
         if (getImportance() != DEFAULT_IMPORTANCE) {
             out.attribute(
                     null, ATT_IMPORTANCE, Integer.toString(getImportance()));
@@ -588,6 +638,7 @@
         JSONObject record = new JSONObject();
         record.put(ATT_ID, getId());
         record.put(ATT_NAME, getName());
+        record.put(ATT_DESC, getDescription());
         if (getImportance() != DEFAULT_IMPORTANCE) {
             record.put(ATT_IMPORTANCE,
                     NotificationListenerService.Ranking.importanceToString(getImportance()));
@@ -718,6 +769,10 @@
         if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
             return false;
         }
+        if (getDescription() != null ? !getDescription().equals(that.getDescription())
+                : that.getDescription() != null) {
+            return false;
+        }
         if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) {
             return false;
         }
@@ -734,6 +789,7 @@
     public int hashCode() {
         int result = getId() != null ? getId().hashCode() : 0;
         result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+        result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
         result = 31 * result + getImportance();
         result = 31 * result + (mBypassDnd ? 1 : 0);
         result = 31 * result + getLockscreenVisibility();
@@ -755,6 +811,7 @@
         return "NotificationChannel{" +
                 "mId='" + mId + '\'' +
                 ", mName=" + mName +
+                ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "") +
                 ", mImportance=" + mImportance +
                 ", mBypassDnd=" + mBypassDnd +
                 ", mLockscreenVisibility=" + mLockscreenVisibility +
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 2b0cd04..852af8a 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -40,6 +40,12 @@
  */
 public final class NotificationChannelGroup implements Parcelable {
 
+    /**
+     * The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at
+     * this limit.
+     */
+    private static final int MAX_TEXT_LENGTH = 1000;
+
     private static final String TAG_GROUP = "channelGroup";
     private static final String ATT_NAME = "name";
     private static final String ATT_ID = "id";
@@ -51,14 +57,16 @@
     /**
      * Creates a notification channel group.
      *
-     * @param id The id of the group. Must be unique per package.
+     * @param id The id of the group. Must be unique per package.  the value may be truncated if
+     *           it is too long.
      * @param name The user visible name of the group. You can rename this group when the system
      *             locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
-     *             broadcast.
+     *             broadcast. <p>The recommended maximum length is 40 characters; the value may be
+     *             truncated if it is too long.
      */
     public NotificationChannelGroup(String id, CharSequence name) {
-        this.mId = id;
-        this.mName = name;
+        this.mId = getTrimmedString(id);
+        this.mName = name != null ? getTrimmedString(name.toString()) : null;
     }
 
     protected NotificationChannelGroup(Parcel in) {
@@ -71,6 +79,13 @@
         in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
     }
 
+    private String getTrimmedString(String input) {
+        if (input != null && input.length() > MAX_TEXT_LENGTH) {
+            return input.substring(0, MAX_TEXT_LENGTH);
+        }
+        return input;
+    }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (mId != null) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 0379970..097df31 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -421,8 +421,12 @@
     /**
      * Creates a notification channel that notifications can be posted to.
      *
-     * This can also be used to restore a deleted channel and to rename an existing channel. All
-     * other fields are ignored for channels that already exist.
+     * This can also be used to restore a deleted channel and to update an existing channel's
+     * name and description. The name and description should only be changed if the locale changes
+     * or in response to the user renaming this channel. For example, if a user has a channel
+     * named 'John Doe' that represents messages from a 'John Doe', and 'John Doe' changes his name
+     * to 'John Smith,' the channel can be renamed to match.
+     * All other fields are ignored for channels that already exist.
      *
      * @param channel  the channel to create.  Note that the created channel may differ from this
      *                 value. If the provided channel is malformed, a RemoteException will be
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index e041457..d5436b7 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,5 +1,6 @@
 package android.app.assist;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.ComponentName;
@@ -1601,23 +1602,22 @@
             return mNode.mChildren != null ? mNode.mChildren.length : 0;
         }
 
-        private void setAutofillId(ViewNode child, boolean forAutoFill, int virtualId) {
-            if (forAutoFill) {
-                child.mAutofillId = new AutofillId(mNode.mAutofillId, virtualId);
-            }
+        @Override
+        public void setAutofillId(@NonNull ViewStructure parent, int virtualId) {
+            mNode.mAutofillId = new AutofillId(parent.getAutofillId(), virtualId);
         }
 
-        private ViewStructure newChild(int index, boolean forAutoFill, int virtualId, int flags) {
+        @Override
+        public ViewStructure newChild(int index) {
             ViewNode node = new ViewNode();
-            setAutofillId(node, forAutoFill, virtualId);
             mNode.mChildren[index] = node;
             return new ViewNodeBuilder(mAssist, node, false);
         }
 
-        private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId) {
+        @Override
+        public ViewStructure asyncNewChild(int index) {
             synchronized (mAssist) {
                 ViewNode node = new ViewNode();
-                setAutofillId(node, forAutoFill, virtualId);
                 mNode.mChildren[index] = node;
                 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
                 mAssist.mPendingAsyncChildren.add(builder);
@@ -1626,26 +1626,6 @@
         }
 
         @Override
-        public ViewStructure newChild(int index) {
-            return newChild(index, false, 0, 0);
-        }
-
-        @Override
-        public ViewStructure newChild(int index, int virtualId, int flags) {
-            return newChild(index, true, virtualId, flags);
-        }
-
-        @Override
-        public ViewStructure asyncNewChild(int index) {
-            return asyncNewChild(index, false, 0);
-        }
-
-        @Override
-        public ViewStructure asyncNewChild(int index, int virtualId, int flags) {
-            return asyncNewChild(index, true, virtualId);
-        }
-
-        @Override
         public void asyncCommit() {
             synchronized (mAssist) {
                 if (!mAsync) {
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 5710ad1..ecdc0ce 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -22,10 +22,13 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -40,6 +43,9 @@
  */
 public final class CompanionDeviceManager {
 
+    private static final boolean DEBUG = false; //TODO
+    private static final String LOG_TAG = "CompanionDeviceManager";
+
     /**
      * A device, returned in the activity result of the {@link IntentSender} received in
      * {@link Callback#onDeviceFound}
@@ -81,7 +87,7 @@
 
     /** @hide */
     public CompanionDeviceManager(
-            @NonNull ICompanionDeviceManager service, @NonNull Context context) {
+            @Nullable ICompanionDeviceManager service, @NonNull Context context) {
         mService = service;
         mContext = context;
     }
@@ -120,6 +126,10 @@
             @NonNull AssociationRequest request,
             @NonNull Callback callback,
             @Nullable Handler handler) {
+        if (!checkFeaturePresent()) {
+            return;
+        }
+
         final Handler finalHandler = handler != null
                 ? handler
                 : new Handler(Looper.getMainLooper());
@@ -153,6 +163,9 @@
      */
     @NonNull
     public List<String> getAssociations() {
+        if (!checkFeaturePresent()) {
+            return Collections.emptyList();
+        }
         try {
             return mService.getAssociations(mContext.getPackageName());
         } catch (RemoteException e) {
@@ -172,6 +185,9 @@
      * @param deviceMacAddress the MAC address of device to disassociate from this app
      */
     public void disassociate(@NonNull String deviceMacAddress) {
+        if (!checkFeaturePresent()) {
+            return;
+        }
         try {
             mService.disassociate(deviceMacAddress, mContext.getPackageName());
         } catch (RemoteException e) {
@@ -181,14 +197,28 @@
 
     /** @hide */
     public void requestNotificationAccess() {
+        if (!checkFeaturePresent()) {
+            return;
+        }
         //TODO implement
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
     /** @hide */
     public boolean haveNotificationAccess() {
+        if (!checkFeaturePresent()) {
+            return false;
+        }
         //TODO implement
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
+    private boolean checkFeaturePresent() {
+        boolean featurePresent = mService == null;
+        if (!featurePresent && DEBUG) {
+            Log.d(LOG_TAG, "Feature " + PackageManager.FEATURE_COMPANION_DEVICE_SETUP
+                    + " not available");
+        }
+        return featurePresent;
+    }
 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4ffc6f9..d75c2ee0 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -620,12 +620,17 @@
             return MODE_IGNORED;
         }
 
-        final String failReason = mExported
-                ? " requires " + missingPerm + ", or grantUriPermission()"
-                : " requires the provider be exported, or grantUriPermission()";
+        final String suffix;
+        if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(mReadPermission)) {
+            suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
+        } else if (mExported) {
+            suffix = " requires " + missingPerm + ", or grantUriPermission()";
+        } else {
+            suffix = " requires the provider be exported, or grantUriPermission()";
+        }
         throw new SecurityException("Permission Denial: reading "
                 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
-                + ", uid=" + uid + failReason);
+                + ", uid=" + uid + suffix);
     }
 
     /** {@hide} */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bd31b03..fb86791 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import static android.content.ContentProvider.maybeAddUserId;
+
 import android.annotation.AnyRes;
 import android.annotation.BroadcastBehavior;
 import android.annotation.IntDef;
@@ -41,7 +43,6 @@
 import android.os.ShellCommand;
 import android.os.StrictMode;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
@@ -49,7 +50,9 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
+
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -67,8 +70,6 @@
 import java.util.Objects;
 import java.util.Set;
 
-import static android.content.ContentProvider.maybeAddUserId;
-
 /**
  * An intent is an abstract description of an operation to be performed.  It
  * can be used with {@link Context#startActivity(Intent) startActivity} to
@@ -3854,9 +3855,23 @@
     public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
 
     /**
-     * A content: URI holding a stream of data associated with the Intent,
-     * used with {@link #ACTION_SEND} to supply the data being sent.
+     * A content: URI holding a stream of data associated with the Intent, used
+     * with {@link #ACTION_SEND} to supply the data being sent.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN} this value
+     * will be automatically promoted to {@link Intent#setClipData(ClipData)}
+     * when that value is not already defined.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O} this value will be
+     * automatically demoted from {@link Intent#getClipData()} when this value
+     * is not already defined.
+     *
+     * @deprecated apps should use {@link Intent#setClipData(ClipData)} and
+     *             {@link Intent#getClipData()} instead of this extra, since
+     *             only those APIs can extend temporary permission grants to the
+     *             underlying resource.
      */
+    @Deprecated
     public static final String EXTRA_STREAM = "android.intent.extra.STREAM";
 
     /**
@@ -5123,6 +5138,8 @@
     private Intent mSelector;
     private ClipData mClipData;
     private int mContentUserHint = UserHandle.USER_CURRENT;
+    /** Token to track instant app launches. Local only; do not copy cross-process. */
+    private String mLaunchToken;
 
     // ---------------------------------------------------------------------
 
@@ -5143,6 +5160,7 @@
         this.mComponent = o.mComponent;
         this.mFlags = o.mFlags;
         this.mContentUserHint = o.mContentUserHint;
+        this.mLaunchToken = o.mLaunchToken;
         if (o.mCategories != null) {
             this.mCategories = new ArraySet<String>(o.mCategories);
         }
@@ -6379,6 +6397,16 @@
         return mContentUserHint;
     }
 
+    /** @hide */
+    public String getLaunchToken() {
+        return mLaunchToken;
+    }
+
+    /** @hide */
+    public void setLaunchToken(String launchToken) {
+        mLaunchToken = launchToken;
+    }
+
     /**
      * Sets the ClassLoader that will be used when unmarshalling
      * any Parcelable values from the extras of this Intent.
@@ -9362,6 +9390,21 @@
                 mContentUserHint = UserHandle.USER_CURRENT;
             }
         }
+
+        // If someone is sending us ClipData, but not EXTRA_STREAM, offer to
+        // downgrade that content for older apps to find
+        if (mClipData != null && mClipData.getItemCount() > 0 && !hasExtra(EXTRA_STREAM)) {
+            final String action = getAction();
+            if (ACTION_SEND.equals(action)) {
+                putExtra(EXTRA_STREAM, mClipData.getItemAt(0).getUri());
+            } else if (ACTION_SEND_MULTIPLE.equals(action)) {
+                final ArrayList<Uri> list = new ArrayList<>();
+                for (int i = 0; i < mClipData.getItemCount(); i++) {
+                    list.add(mClipData.getItemAt(i).getUri());
+                }
+                putExtra(EXTRA_STREAM, list);
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 0b3742f..ffc7719 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -920,7 +920,7 @@
 
     /**
      * Category for apps which are primarily social apps, such as messaging,
-     * communication, or social network apps.
+     * communication, email, or social network apps.
      *
      * @see #category
      */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6dd1833..bb35928 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -46,6 +46,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -58,6 +59,8 @@
 
 import com.android.internal.util.ArrayUtils;
 
+import dalvik.system.VMRuntime;
+
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -2233,6 +2236,15 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports {@link android.companion.CompanionDeviceManager#associate associating}
+     * with devices via {@link android.companion.CompanionDeviceManager}.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_COMPANION_DEVICE_SETUP
+            = "android.software.companion_device_setup";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device can perform backup and restore operations on installed applications.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -4252,8 +4264,14 @@
     @Deprecated
     public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId) {
-        Log.w(TAG, "STAHP USING HIDDEN APIS KTHX");
-        return queryBroadcastReceiversAsUser(intent, flags, userId);
+        final String msg = "Shame on you for calling the hidden API "
+                + "queryBroadcastReceivers(). Shame!";
+        if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.O) {
+            throw new UnsupportedOperationException(msg);
+        } else {
+            Log.d(TAG, msg);
+            return queryBroadcastReceiversAsUser(intent, flags, userId);
+        }
     }
 
     /**
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index 091cc26..0edbc70 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -26,6 +26,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -44,12 +45,14 @@
         private final @NonNull String mProviderAuthority;
         private final @NonNull String mProviderPackage;
         private final @NonNull String mQuery;
+        private final @Nullable List<List<String>> mCerts;
 
         public ProviderResourceEntry(@NonNull String authority, @NonNull String pkg,
-                @NonNull String query) {
+                @NonNull String query, @Nullable List<List<String>> certs) {
             mProviderAuthority = authority;
             mProviderPackage = pkg;
             mQuery = query;
+            mCerts = certs;
         }
 
         public @NonNull String getAuthority() {
@@ -63,6 +66,10 @@
         public @NonNull String getQuery() {
             return mQuery;
         }
+
+        public @Nullable List<List<String>> getCerts() {
+            return mCerts;
+        }
     }
 
     // A class represents font element in xml file which points a file in resource.
@@ -144,12 +151,33 @@
         String authority = array.getString(R.styleable.FontFamily_fontProviderAuthority);
         String providerPackage = array.getString(R.styleable.FontFamily_fontProviderPackage);
         String query = array.getString(R.styleable.FontFamily_fontProviderQuery);
+        int certsId = array.getResourceId(R.styleable.FontFamily_fontProviderCerts, 0);
         array.recycle();
         if (authority != null && providerPackage != null && query != null) {
             while (parser.next() != XmlPullParser.END_TAG) {
                 skip(parser);
             }
-            return new ProviderResourceEntry(authority, providerPackage, query);
+            List<List<String>> certs = null;
+            if (certsId != 0) {
+                TypedArray typedArray = resources.obtainTypedArray(certsId);
+                if (typedArray.length() > 0) {
+                    certs = new ArrayList<>();
+                    boolean isArrayOfArrays = typedArray.getResourceId(0, 0) != 0;
+                    if (isArrayOfArrays) {
+                        for (int i = 0; i < typedArray.length(); i++) {
+                            int certId = typedArray.getResourceId(i, 0);
+                            String[] certsArray = resources.getStringArray(certId);
+                            List<String> certsList = Arrays.asList(certsArray);
+                            certs.add(certsList);
+                        }
+                    } else {
+                        String[] certsArray = resources.getStringArray(certsId);
+                        List<String> certsList = Arrays.asList(certsArray);
+                        certs.add(certsList);
+                    }
+                }
+            }
+            return new ProviderResourceEntry(authority, providerPackage, query, certs);
         }
         List<FontFileResourceEntry> fonts = new ArrayList<>();
         while (parser.next() != XmlPullParser.END_TAG) {
diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java
index fbd039d..5f42f30 100644
--- a/core/java/android/database/PageViewCursor.java
+++ b/core/java/android/database/PageViewCursor.java
@@ -19,6 +19,7 @@
 
 import android.annotation.Nullable;
 import android.content.ContentResolver;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.util.MathUtils;
@@ -33,22 +34,24 @@
  *
  * @hide
  */
-public final class PageViewCursor extends CrossProcessCursorWrapper {
+public final class PageViewCursor extends CursorWrapper implements CrossProcessCursor {
 
     /**
-     * An extra added to results that are auto-paged using the wrapper.
+     * An in internal extra added to results that are auto-paged using the wrapper.
      */
     public static final String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
 
     private static final String TAG = "PageViewCursor";
-    private static final boolean DEBUG = false;
-    private static final boolean VERBOSE = false;
+    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+    private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
 
     private final int mOffset;  // aka first index
     private final int mCount;
     private final Bundle mExtras;
 
+    private @Nullable CursorWindow mWindow;
     private int mPos = -1;
+    private int mWindowFillCount = 0;
 
     /**
      * @see PageViewCursor#wrap(Cursor, Bundle)
@@ -195,6 +198,33 @@
         return mCount;
     }
 
+    @Override
+    public boolean getWantsAllOnMoveCalls() {
+        return false;  // we want bulk cursor adapter to lift data into a CursorWindow.
+    }
+
+    @Override
+    public CursorWindow getWindow() {
+        assert(mPos == -1 || mPos == 0);
+        if (mWindow == null) {
+           mWindow = new CursorWindow("PageViewCursorWindow");
+           fillWindow(0, mWindow);
+        }
+
+        return mWindow;
+    }
+
+    @Override
+    public void fillWindow(int position, CursorWindow window) {
+        assert(window == mWindow);
+
+        if (mWindowFillCount++ > 0) {
+            Log.w(TAG, "Re-filling window on paged cursor! Reduce ContentResolver.QUERY_ARG_LIMIT");
+        }
+
+        DatabaseUtils.cursorFillWindow(this, position, window);
+    }
+
     /**
      * Wraps the cursor such that it will honor paging args (if present), AND if the cursor
      * does not report paging size.
@@ -209,12 +239,19 @@
                 || queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT));
 
         if (!hasPagingArgs) {
-            if (VERBOSE) Log.d(TAG, "No-wrap: No paging args in request.");
+            if (VERBOSE) Log.v(TAG, "No-wrap: No paging args in request.");
             return cursor;
         }
 
         if (hasPagedResponseDetails(cursor.getExtras())) {
-            if (VERBOSE) Log.d(TAG, "No-wrap. Cursor has paging details.");
+            if (VERBOSE) Log.v(TAG, "No-wrap. Cursor has paging details.");
+            return cursor;
+        }
+
+        // Cursors that want all calls aren't compatible with our way
+        // of doing business. TODO: Cover this case in CTS.
+        if (cursor.getWantsAllOnMoveCalls()) {
+            Log.w(TAG, "Unable to wrap cursor that wants to hear about move calls.");
             return cursor;
         }
 
diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java
new file mode 100644
index 0000000..745642e
--- /dev/null
+++ b/core/java/android/os/TestLooperManager.java
@@ -0,0 +1,209 @@
+/*
+ * 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 android.os;
+
+import android.util.ArraySet;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Blocks a looper from executing any messages, and allows the holder of this object
+ * to control when and which messages get executed until it is released.
+ * <p>
+ * A TestLooperManager should be acquired using
+ * {@link android.app.Instrumentation#acquireLooperManager}. Until {@link #release()} is called,
+ * the Looper thread will not execute any messages except when {@link #execute(Message)} is called.
+ * The test code may use {@link #next()} to acquire messages that have been queued to this
+ * {@link Looper}/{@link MessageQueue} and then {@link #execute} to run any that desires.
+ */
+public class TestLooperManager {
+
+    private static final ArraySet<Looper> sHeldLoopers = new ArraySet<>();
+
+    private final MessageQueue mQueue;
+    private final Looper mLooper;
+    private final LinkedBlockingQueue<MessageExecution> mExecuteQueue = new LinkedBlockingQueue<>();
+
+    private boolean mReleased;
+    private boolean mLooperBlocked;
+
+    /**
+     * @hide
+     */
+    public TestLooperManager(Looper looper) {
+        synchronized (sHeldLoopers) {
+            if (sHeldLoopers.contains(looper)) {
+                throw new RuntimeException("TestLooperManager already held for this looper");
+            }
+            sHeldLoopers.add(looper);
+        }
+        mLooper = looper;
+        mQueue = mLooper.getQueue();
+        // Post a message that will keep the looper blocked as long as we are dispatching.
+        new Handler(looper).post(new LooperHolder());
+    }
+
+    /**
+     * Returns the {@link MessageQueue} this object is wrapping.
+     */
+    public MessageQueue getQueue() {
+        checkReleased();
+        return mQueue;
+    }
+
+    /**
+     * Returns the next message that should be executed by this queue, may block
+     * if no messages are ready.
+     * <p>
+     * Callers should always call {@link #recycle(Message)} on the message when all
+     * interactions with it have completed.
+     */
+    public Message next() {
+        // Wait for the looper block to come up, to make sure we don't accidentally get
+        // the message for the block.
+        while (!mLooperBlocked) {
+            synchronized (this) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        checkReleased();
+        return mQueue.next();
+    }
+
+    /**
+     * Releases the looper to continue standard looping and processing of messages,
+     * no further interactions with TestLooperManager will be allowed after
+     * release() has been called.
+     */
+    public void release() {
+        synchronized (sHeldLoopers) {
+            sHeldLoopers.remove(mLooper);
+        }
+        checkReleased();
+        mReleased = true;
+        mExecuteQueue.add(new MessageExecution());
+    }
+
+    /**
+     * Executes the given message on the Looper thread this wrapper is
+     * attached to.
+     * <p>
+     * Execution will happen on the Looper's thread (whether it is the current thread
+     * or not), but all RuntimeExceptions encountered while executing the message will
+     * be thrown on the calling thread.
+     */
+    public void execute(Message message) {
+        checkReleased();
+        if (Looper.myLooper() == mLooper) {
+            // This is being called from the thread it should be executed on, we can just dispatch.
+            message.target.dispatchMessage(message);
+        } else {
+            MessageExecution execution = new MessageExecution();
+            execution.m = message;
+            synchronized (execution) {
+                mExecuteQueue.add(execution);
+                // Wait for the message to be executed.
+                try {
+                    execution.wait();
+                } catch (InterruptedException e) {
+                }
+                if (execution.response != null) {
+                    throw new RuntimeException(execution.response);
+                }
+            }
+        }
+    }
+
+    /**
+     * Called to indicate that a Message returned by {@link #next()} has been parsed
+     * and should be recycled.
+     */
+    public void recycle(Message msg) {
+        checkReleased();
+        msg.recycleUnchecked();
+    }
+
+    /**
+     * Returns true if there are any queued messages that match the parameters.
+     *
+     * @param h      the value of {@link Message#getTarget()}
+     * @param what   the value of {@link Message#what}
+     * @param object the value of {@link Message#obj}, null for any
+     */
+    public boolean hasMessages(Handler h, Object object, int what) {
+        checkReleased();
+        return mQueue.hasMessages(h, what, object);
+    }
+
+    /**
+     * Returns true if there are any queued messages that match the parameters.
+     *
+     * @param h      the value of {@link Message#getTarget()}
+     * @param r      the value of {@link Message#getCallback()}
+     * @param object the value of {@link Message#obj}, null for any
+     */
+    public boolean hasMessages(Handler h, Object object, Runnable r) {
+        checkReleased();
+        return mQueue.hasMessages(h, r, object);
+    }
+
+    private void checkReleased() {
+        if (mReleased) {
+            throw new RuntimeException("release() has already be called");
+        }
+    }
+
+    private class LooperHolder implements Runnable {
+        @Override
+        public void run() {
+            synchronized (TestLooperManager.this) {
+                mLooperBlocked = true;
+                TestLooperManager.this.notify();
+            }
+            while (!mReleased) {
+                try {
+                    final MessageExecution take = mExecuteQueue.take();
+                    if (take.m != null) {
+                        processMessage(take);
+                    }
+                } catch (InterruptedException e) {
+                }
+            }
+            synchronized (TestLooperManager.this) {
+                mLooperBlocked = false;
+            }
+        }
+
+        private void processMessage(MessageExecution mex) {
+            synchronized (mex) {
+                try {
+                    mex.m.target.dispatchMessage(mex.m);
+                    mex.response = null;
+                } catch (Throwable t) {
+                    mex.response = t;
+                }
+                mex.notifyAll();
+            }
+        }
+    }
+
+    private static class MessageExecution {
+        private Message m;
+        private Throwable response;
+    }
+}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index d9c749a..4d14277 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -82,6 +82,7 @@
  * @attr ref android.R.styleable#Preference_defaultValue
  * @attr ref android.R.styleable#Preference_shouldDisableView
  * @attr ref android.R.styleable#Preference_recycleEnabled
+ * @attr ref android.R.styleable#Preference_singleLineTitle
  */
 public class Preference implements Comparable<Preference> {
     /**
@@ -133,6 +134,7 @@
     private boolean mDependencyMet = true;
     private boolean mParentDependencyMet = true;
     private boolean mRecycleEnabled = true;
+    private boolean mSingleLineTitle = true;
 
     /**
      * @see #setShouldDisableView(boolean)
@@ -296,6 +298,10 @@
                 case com.android.internal.R.styleable.Preference_recycleEnabled:
                     mRecycleEnabled = a.getBoolean(attr, mRecycleEnabled);
                     break;
+
+                case com.android.internal.R.styleable.Preference_singleLineTitle:
+                    mSingleLineTitle = a.getBoolean(attr, mSingleLineTitle);
+                    break;
             }
         }
         a.recycle();
@@ -597,6 +603,7 @@
             if (!TextUtils.isEmpty(title)) {
                 titleView.setText(title);
                 titleView.setVisibility(View.VISIBLE);
+                titleView.setSingleLine(mSingleLineTitle);
             } else {
                 titleView.setVisibility(View.GONE);
             }
@@ -903,6 +910,27 @@
     }
 
     /**
+     * Sets whether to constrain the title of this Preference to a single line instead of
+     * letting it wrap onto multiple lines.
+     *
+     * @param singleLineTitle set {@code true} if the title should be constrained to one line
+     */
+    public void setSingleLineTitle(boolean singleLineTitle) {
+        mSingleLineTitle = singleLineTitle;
+        notifyChanged();
+    }
+
+    /**
+     * Gets whether the title of this preference is constrained to a single line.
+     *
+     * @see #setSingleLineTitle(boolean)
+     * @return {@code true} if the title of this preference is constrained to a single line
+     */
+    public boolean isSingleLineTitle() {
+        return mSingleLineTitle;
+    }
+
+    /**
      * Returns a unique ID for this Preference.  This ID should be unique across all
      * Preference objects in a hierarchy.
      *
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index dac8354..b4f19d8 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8983,6 +8983,11 @@
          * value of this extra is a {@code String} and should be the value of {@link
          * android.accounts.Account#hashCode()} for some account returned by {@link
          * android.accounts.AccountManager#getAccounts()}.
+         * <p>
+         * If the extra is not specified, the app can decide which account to use.
+         * <p>
+         * If the account specified in the extra cannot be used for any reason (account missing, not
+         * usable by the app, etc), the message should not be sent.
          */
         public static final String EXTRA_SENDER_ACCOUNT_HASH =
                 "android.provider.extra.SENDER_ACCOUNT_HASH";
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 84443e9..fd9d4db 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -15,7 +15,6 @@
  */
 package android.provider;
 
-import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
@@ -42,9 +41,10 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Utility class to deal with Font ContentProviders.
@@ -207,11 +207,12 @@
             return info;
         }
 
-        Set<byte[]> signatures;
+        List<byte[]> signatures;
         try {
             PackageInfo packageInfo = mPackageManager.getPackageInfo(info.packageName,
                     PackageManager.GET_SIGNATURES);
-            signatures = convertToSet(packageInfo.signatures);
+            signatures = convertToByteArrayList(packageInfo.signatures);
+            Collections.sort(signatures, sByteArrayComparator);
         } catch (PackageManager.NameNotFoundException e) {
             Log.e(TAG, "Can't find content provider " + providerAuthority, e);
             receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
@@ -219,8 +220,10 @@
         }
         List<List<byte[]>> requestCertificatesList = request.getCertificates();
         for (int i = 0; i < requestCertificatesList.size(); ++i) {
-            final Set<byte[]> requestCertificates = convertToSet(requestCertificatesList.get(i));
-            if (signatures.equals(requestCertificates)) {
+            // Make a copy so we can sort it without modifying the incoming data.
+            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
+            Collections.sort(requestSignatures, sByteArrayComparator);
+            if (equalsByteArrayList(signatures, requestSignatures)) {
                 return info;
             }
         }
@@ -229,20 +232,38 @@
         return null;
     }
 
-    private Set<byte[]> convertToSet(Signature[] signatures) {
-        Set<byte[]> shas = new HashSet<>();
+    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
+        if (l.length != r.length) {
+            return l.length - r.length;
+        }
+        for (int i = 0; i < l.length; ++i) {
+            if (l[i] != r[i]) {
+                return l[i] - r[i];
+            }
+        }
+        return 0;
+    };
+
+    private boolean equalsByteArrayList(List<byte[]> signatures, List<byte[]> requestSignatures) {
+        if (signatures.size() != requestSignatures.size()) {
+            return false;
+        }
+        for (int i = 0; i < signatures.size(); ++i) {
+            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private List<byte[]> convertToByteArrayList(Signature[] signatures) {
+        List<byte[]> shas = new ArrayList<>();
         for (int i = 0; i < signatures.length; ++i) {
             shas.add(signatures[i].toByteArray());
         }
         return shas;
     }
 
-    private Set<byte[]> convertToSet(List<byte[]> certs) {
-        Set<byte[]> shas = new HashSet<>();
-        shas.addAll(certs);
-        return shas;
-    }
-
     /** @hide */
     @VisibleForTesting
     public void getFontFromProvider(FontRequest request, ResultReceiver receiver,
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index c4684e7..93adf83 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -534,6 +534,14 @@
         }
 
         /**
+         * Used to trigger special logic for directories.
+         * @hide
+         */
+        public static final Uri getDirectoryUri(String volumeName) {
+            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + "/dir");
+        }
+
+        /**
          * Fields for master table for all media files.
          * Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
          */
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index ebe02c2..47e7803 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -49,12 +49,14 @@
 
     private final ArrayList<AutofillId> mFieldIds;
     private final ArrayList<AutofillValue> mFieldValues;
+    private final ArrayList<RemoteViews> mFieldPresentations;
     private final RemoteViews mPresentation;
     private final IntentSender mAuthentication;
 
     private Dataset(Builder builder) {
         mFieldIds = builder.mFieldIds;
         mFieldValues = builder.mFieldValues;
+        mFieldPresentations = builder.mFieldPresentations;
         mPresentation = builder.mPresentation;
         mAuthentication = builder.mAuthentication;
     }
@@ -70,6 +72,12 @@
     }
 
     /** @hide */
+    public RemoteViews getFieldPresentation(int index) {
+        final RemoteViews customPresentation = mFieldPresentations.get(index);
+        return customPresentation != null ? customPresentation : mPresentation;
+    }
+
+    /** @hide */
     public @Nullable RemoteViews getPresentation() {
         return mPresentation;
     }
@@ -91,6 +99,8 @@
         return new StringBuilder("Dataset [")
                 .append(", fieldIds=").append(mFieldIds)
                 .append(", fieldValues=").append(mFieldValues)
+                .append(", fieldPresentations=")
+                .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
                 .append(", hasPresentation=").append(mPresentation != null)
                 .append(", hasAuthentication=").append(mAuthentication != null)
                 .append(']').toString();
@@ -103,6 +113,7 @@
     public static final class Builder {
         private ArrayList<AutofillId> mFieldIds;
         private ArrayList<AutofillValue> mFieldValues;
+        private ArrayList<RemoteViews> mFieldPresentations;
         private RemoteViews mPresentation;
         private IntentSender mAuthentication;
         private boolean mDestroyed;
@@ -118,6 +129,15 @@
         }
 
         /**
+         * Creates a new builder for a dataset where each field will be visualized independently.
+         *
+         * <p>When using this constructor, fields must be set through
+         * {@link #setValue(AutofillId, AutofillValue, RemoteViews)}.
+         */
+        public Builder() {
+        }
+
+        /**
          * Requires a dataset authentication before autofilling the activity with this dataset.
          *
          * <p>This method is called when you need to provide an authentication
@@ -175,24 +195,54 @@
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
          * @param value value to be auto filled.
          * @return This builder.
+         * @throws IllegalStateException if the builder was constructed without a presentation
+         * ({@link RemoteViews}).
          */
         public @NonNull Builder setValue(@NonNull AutofillId id, @NonNull AutofillValue value) {
             throwIfDestroyed();
+            if (mPresentation == null) {
+                throw new IllegalStateException("Dataset presentation not set on constructor");
+            }
+            setValueAndPresentation(id, value, null);
+            return this;
+        }
+
+        /**
+         * Sets the value of a field, usin a custom presentation to visualize it.
+         *
+         * @param id id returned by {@link
+         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
+         * @param value value to be auto filled.
+         * @param presentation The presentation used to visualize this field.
+         * @return This builder.
+         */
+        public @NonNull Builder setValue(@NonNull AutofillId id, @NonNull AutofillValue value,
+                @NonNull RemoteViews presentation) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(presentation, "presentation cannot be null");
+            setValueAndPresentation(id, value, presentation);
+            return this;
+        }
+
+        private void setValueAndPresentation(AutofillId id, AutofillValue value,
+                RemoteViews presentation) {
             Preconditions.checkNotNull(id, "id cannot be null");
             Preconditions.checkNotNull(value, "value cannot be null");
             if (mFieldIds != null) {
                 final int existingIdx = mFieldIds.indexOf(id);
                 if (existingIdx >= 0) {
                     mFieldValues.set(existingIdx, value);
-                    return this;
+                    mFieldPresentations.set(existingIdx, presentation);
+                    return;
                 }
             } else {
                 mFieldIds = new ArrayList<>();
                 mFieldValues = new ArrayList<>();
+                mFieldPresentations = new ArrayList<>();
             }
             mFieldIds.add(id);
             mFieldValues.add(value);
-            return this;
+            mFieldPresentations.add(presentation);
         }
 
         /**
@@ -234,6 +284,7 @@
         parcel.writeParcelable(mPresentation, flags);
         parcel.writeTypedArrayList(mFieldIds, flags);
         parcel.writeTypedArrayList(mFieldValues, flags);
+        parcel.writeParcelableList(mFieldPresentations, flags);
         parcel.writeParcelable(mAuthentication, flags);
     }
 
@@ -243,15 +294,22 @@
             // Always go through the builder to ensure the data ingested by
             // the system obeys the contract of the builder to avoid attacks
             // using specially crafted parcels.
-            final Builder builder = new Builder(parcel.readParcelable(null));
+            final RemoteViews presentation = parcel.readParcelable(null);
+            final Builder builder = (presentation == null)
+                    ? new Builder()
+                    : new Builder(presentation);
             final ArrayList<AutofillId> ids = parcel.readTypedArrayList(null);
             final ArrayList<AutofillValue> values = parcel.readTypedArrayList(null);
+            final ArrayList<RemoteViews> presentations = new ArrayList<>();
+            parcel.readParcelableList(presentations, null);
             final int idCount = (ids != null) ? ids.size() : 0;
             final int valueCount = (values != null) ? values.size() : 0;
             for (int i = 0; i < idCount; i++) {
                 final AutofillId id = ids.get(i);
                 final AutofillValue value = (valueCount > i) ? values.get(i) : null;
-                builder.setValue(id, value);
+                final RemoteViews fieldPresentation = presentations.isEmpty() ? null
+                        : presentations.get(i);
+                builder.setValueAndPresentation(id, value, fieldPresentation);
             }
             builder.setAuthentication(parcel.readParcelable(null));
             return builder.build();
diff --git a/core/java/android/service/vr/IPersistentVrStateCallbacks.aidl b/core/java/android/service/vr/IPersistentVrStateCallbacks.aidl
new file mode 100644
index 0000000..7de8b63
--- /dev/null
+++ b/core/java/android/service/vr/IPersistentVrStateCallbacks.aidl
@@ -0,0 +1,24 @@
+/**
+ * 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 android.service.vr;
+
+/** @hide */
+oneway interface IPersistentVrStateCallbacks {
+
+    void onPersistentVrStateChanged(in boolean enabled);
+
+}
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 6034c18..fce06d6 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -17,6 +17,7 @@
 package android.service.vr;
 
 import android.service.vr.IVrStateCallbacks;
+import android.service.vr.IPersistentVrStateCallbacks;
 
 /** @hide */
 interface IVrManager {
@@ -36,6 +37,20 @@
     void unregisterListener(in IVrStateCallbacks cb);
 
     /**
+     * Add a callback to be notified when persistent VR mode state changes.
+     *
+     * @param cb the callback instance to add.
+     */
+    void registerPersistentVrStateListener(in IPersistentVrStateCallbacks cb);
+
+    /**
+     * Remove the callack from the current set of registered callbacks.
+     *
+     * @param cb the callback to remove.
+     */
+    void unregisterPersistentVrStateListener(in IPersistentVrStateCallbacks cb);
+
+    /**
      * Return current VR mode state.
      *
      * @return {@code true} if VR mode is enabled.
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 04596fa..70f9bdd 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.FontListParser;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -106,8 +107,16 @@
         private final float mStyleValue;
 
         public Axis(int tag, float styleValue) {
-            this.mTag = tag;
-            this.mStyleValue = styleValue;
+            mTag = tag;
+            mStyleValue = styleValue;
+        }
+
+        public Axis(@NonNull String tagString, float styleValue) {
+            if (!FontListParser.isValidTag(tagString)) {
+                throw new IllegalArgumentException("Invalid tag pattern: " + tagString);
+            }
+            mTag = FontListParser.makeTag(tagString);
+            mStyleValue = styleValue;
         }
 
         /**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5494377..6dedbde 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -50,7 +50,7 @@
  * <li>The real display area specifies the part of the display that contains content
  * including the system decorations.  Even so, the real display area may be smaller than the
  * physical size of the display if the window manager is emulating a smaller display
- * using (adb shell am display-size).  Use the following methods to query the
+ * using (adb shell wm size).  Use the following methods to query the
  * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li>
  * </ul>
  * </p><p>
@@ -947,7 +947,7 @@
      * The size is adjusted based on the current rotation of the display.
      * </p><p>
      * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell am display-size).
+     * window manager is emulating a smaller display (using adb shell wm size).
      * </p>
      *
      * @param outSize Set to the real size of the display.
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 350675f..6c73b9b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7275,11 +7275,16 @@
      * fills in all data that can be inferred from the view itself.
      * @param flags optional flags (currently {@code 0}).
      */
-    @CallSuper
     public void onProvideAutofillStructure(ViewStructure structure, int flags) {
         onProvideStructureForAssistOrAutofill(structure, true);
     }
 
+    private void setAutofillId(ViewStructure structure) {
+        // The autofill id needs to be unique, but its value doesn't matter,
+        // so it's better to reuse the accessibility id to save space.
+        structure.setAutofillId(getAccessibilityViewId());
+    }
+
     private void onProvideStructureForAssistOrAutofill(ViewStructure structure,
             boolean forAutofill) {
         final int id = mID;
@@ -7299,13 +7304,11 @@
         }
 
         if (forAutofill) {
+            setAutofillId(structure);
             final @AutofillType int autofillType = getAutofillType();
             // Don't need to fill autofill info if view does not support it.
             // For example, only TextViews that are editable support autofill
             if (autofillType != AUTOFILL_TYPE_NONE) {
-                // The autofill id needs to be unique, but its value doesn't matter, so it's better
-                // to reuse the accessibility id to save space.
-                structure.setAutofillId(getAccessibilityViewId());
                 structure.setAutofillType(autofillType);
                 structure.setAutofillHint(getAutofillHint());
                 structure.setAutofillValue(getAutofillValue());
@@ -7404,6 +7407,9 @@
 
     private void onProvideVirtualStructureForAssistOrAutofill(ViewStructure structure,
             boolean forAutofill) {
+        if (forAutofill) {
+            setAutofillId(structure);
+        }
         // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
         // this method should take a boolean with the type of request.
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
@@ -7671,6 +7677,11 @@
                 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
                 ViewStructure child = structure.newChild(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();
             }
@@ -7707,9 +7718,7 @@
         boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked();
         if (!blocked) {
             if (forAutofill) {
-                // The autofill id needs to be unique, but its value doesn't matter,
-                // so it's better to reuse the accessibility id to save space.
-                structure.setAutofillId(getAccessibilityViewId());
+                setAutofillId(structure);
                 // NOTE: flags are not currently supported, hence 0
                 onProvideAutofillStructure(structure, 0);
                 onProvideAutofillVirtualStructure(structure, 0);
@@ -17892,7 +17901,8 @@
             // This case should hopefully never or seldom happen
             canvas = new Canvas(bitmap);
         }
-
+        boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled();
+        canvas.setHwBitmapsInSwModeEnabled(true);
         if ((backgroundColor & 0xff000000) != 0) {
             bitmap.eraseColor(backgroundColor);
         }
@@ -17920,6 +17930,7 @@
 
         canvas.restoreToCount(restoreCount);
         canvas.setBitmap(null);
+        canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode);
 
         if (attachInfo != null) {
             // Restore the cached Canvas for our siblings
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 40e0285..0c669f3 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -44,7 +45,7 @@
      * Sets the name of the identifier for this view.
      *
      * <p>Typically used when adding virtual children (through
-     * {@link #asyncNewChild(int, int, int)}) that does not map to Android {@link View}
+     * {@link #asyncNewChild(int)}) that does not map to Android {@link View}
      * - otherwise, it's better to call {@link #setId(int, String, String, String)}.
      *
      * @param entryName The entry name of the view's identifier, or {@code null} if there is none.
@@ -280,20 +281,6 @@
     public abstract ViewStructure newChild(int index);
 
     /**
-     * Create a new child {@link ViewStructure} in this view for autofill purposes.
-     *
-     * @param index the index (in the list of children) to put the new child at (see
-     *            {@link #addChildCount(int)} and {@link #setChildCount(int)}.
-     * @param virtualId an opaque ID to the Android System (although it could be meaningful to the
-     *            {@link View} creating the {@link ViewStructure}), but it's the same id used on
-     *            {@link View#autofill(android.util.SparseArray)}.
-     * @param flags currently {@code 0}.
-     *
-     * @return Returns an fresh {@link ViewStructure} ready to be filled in.
-     */
-    public abstract ViewStructure newChild(int index, int virtualId, int flags);
-
-    /**
      * Like {@link #newChild}, but allows the caller to asynchronously populate the returned
      * child.  It can transfer the returned {@link ViewStructure} to another thread for it
      * to build its content (and children etc).  Once done, some thread must call
@@ -304,25 +291,13 @@
     public abstract ViewStructure asyncNewChild(int index);
 
     /**
-     * Like {@link #newChild(int, int, int)}, but allows the caller to asynchronously
-     * populate the returned child.
+     * Sets the {@link AutofillId} for this virtual node.
      *
-     * <p>It can transfer the returned {@link ViewStructure} to another thread for it to build its
-     * content (and children etc).
-     *
-     * <p>Once done, some thread must call {@link #asyncCommit()} to tell the containing
-     * {@link ViewStructure} that the async population is done.
-     *
-     * @param index the index (in the list of children) to put the new child at (see
-     *            {@link #addChildCount(int)} and {@link #setChildCount(int)}.
-     * @param virtualId an opaque ID to the Android System (although it could be meaningful to the
-     *            {@link View} creating the {@link ViewStructure}), but it's the same id used on
+     * @param parent parent node.
+     * @param virtualId an opaque ID to the Android System; it's the same id used on
      *            {@link View#autofill(android.util.SparseArray)}.
-     * @param flags currently {@code 0}.
-     *
-     * @return Returns an fresh {@link ViewStructure} ready to be filled in.
      */
-    public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags);
+    public abstract void setAutofillId(@NonNull ViewStructure parent, int virtualId);
 
     /**
      * Sets the {@link View#getAutofillType()} that can be used to autofill this node.
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 59881b5..a6a9db4 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -132,7 +132,7 @@
 
     private CharSequence mDescFormat;
 
-    private boolean mAttached;
+    private boolean mRegistered;
 
     private Calendar mTime;
     private String mTimeZone;
@@ -252,7 +252,7 @@
         }
 
         createTime(mTimeZone);
-        // Wait until onAttachedToWindow() to handle the ticker
+        // Wait until registering for events to handle the ticker
         chooseFormat(false);
     }
 
@@ -503,12 +503,9 @@
         boolean hadSeconds = mHasSeconds;
         mHasSeconds = DateFormat.hasSeconds(mFormat);
 
-        if (handleTicker && mAttached && hadSeconds != mHasSeconds) {
-            if (hadSeconds) {
-                getHandler().removeCallbacks(mTicker);
-            } else if (getVisibility() == VISIBLE) {
-                mTicker.run();
-            }
+        if (handleTicker && mRegistered && hadSeconds != mHasSeconds) {
+            if (hadSeconds) getHandler().removeCallbacks(mTicker);
+            else mTicker.run();
         }
     }
 
@@ -520,50 +517,27 @@
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        if (!mAttached) {
-            mAttached = true;
+    public void onVisibilityAggregated(boolean isVisible) {
+        if (!mRegistered && isVisible) {
+            mRegistered = true;
 
             registerReceiver();
             registerObserver();
 
             createTime(mTimeZone);
 
-            if (getVisibility() == VISIBLE) {
-                if (mHasSeconds) {
-                    mTicker.run();
-                } else {
-                    onTimeChanged();
-                }
+            if (mHasSeconds) {
+                mTicker.run();
+            } else {
+                onTimeChanged();
             }
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        if (mAttached) {
+        } else if (mRegistered && !isVisible) {
             unregisterReceiver();
             unregisterObserver();
 
             getHandler().removeCallbacks(mTicker);
 
-            mAttached = false;
-        }
-    }
-
-    @Override
-    public void onVisibilityAggregated(boolean isVisible) {
-        if (mAttached) {
-            if (isVisible && mHasSeconds) {
-                mTicker.run();
-            } else {
-                getHandler().removeCallbacks(mTicker);
-            }
-            onTimeChanged();
+            mRegistered = false;
         }
     }
 
@@ -586,7 +560,7 @@
     }
 
     private void registerObserver() {
-        if (mAttached) {
+        if (mRegistered) {
             if (mFormatChangeObserver == null) {
                 mFormatChangeObserver = new FormatChangeObserver(getHandler());
             }
@@ -613,11 +587,9 @@
     }
 
     private void onTimeChanged() {
-        if (getVisibility() == VISIBLE) {
-            mTime.setTimeInMillis(System.currentTimeMillis());
-            setText(DateFormat.format(mFormat, mTime));
-            setContentDescription(DateFormat.format(mDescFormat, mTime));
-        }
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        setText(DateFormat.format(mFormat, mTime));
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
     }
 
     /** @hide */
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 83cc9f0..6e9e350 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -129,21 +129,35 @@
         }
 
         final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName);
+        final String childId;
         if (Document.MIME_TYPE_DIR.equals(mimeType)) {
             if (!file.mkdir()) {
                 throw new IllegalStateException("Failed to mkdir " + file);
             }
+            childId = getDocIdForFile(file);
+            addFolderToMediaStore(getFileForDocId(childId, true));
         } else {
             try {
                 if (!file.createNewFile()) {
                     throw new IllegalStateException("Failed to touch " + file);
                 }
+                childId = getDocIdForFile(file);
             } catch (IOException e) {
                 throw new IllegalStateException("Failed to touch " + file + ": " + e);
             }
         }
 
-        return getDocIdForFile(file);
+        return childId;
+    }
+
+    private void addFolderToMediaStore(File visibleFolder) {
+        assert(visibleFolder.isDirectory());
+
+        final ContentResolver resolver = getContext().getContentResolver();
+        final Uri uri = MediaStore.Files.getDirectoryUri("external");
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
+        resolver.insert(uri, values);
     }
 
     @Override
@@ -193,7 +207,9 @@
     private void moveInMediaStore(File oldVisibleFile, File newVisibleFile) {
         if (newVisibleFile != null) {
             final ContentResolver resolver = getContext().getContentResolver();
-            final Uri externalUri = MediaStore.Files.getContentUri("external");
+            final Uri externalUri = newVisibleFile.isDirectory()
+                    ? MediaStore.Files.getDirectoryUri("external")
+                    : MediaStore.Files.getContentUri("external");
 
             ContentValues values = new ContentValues();
             values.put(MediaStore.Files.FileColumns.DATA, newVisibleFile.getAbsolutePath());
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 af5fca2..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 \
@@ -286,7 +283,6 @@
     libhwbinder \
     libvintf \
     libnativewindow \
-    libtextclassifier \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index fb7c5c4..4e68602 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -34,12 +34,16 @@
 
 #include <hwui/MinikinSkia.h>
 #include <hwui/Typeface.h>
+#include <utils/FatVector.h>
 #include <minikin/FontFamily.h>
 
 #include <memory>
 
 namespace android {
 
+// Must be same with Java constant in Typeface.Builder. See Typeface.java
+constexpr jint RESOLVE_BY_FONT_TABLE = -1;
+
 struct NativeFamilyBuilder {
     uint32_t langId;
     int variant;
@@ -81,24 +85,53 @@
     delete family;
 }
 
-static void addSkTypeface(jlong builderPtr, sk_sp<SkTypeface> face, const void* fontData,
-        size_t fontSize, int ttcIndex, jint givenWeight, jboolean givenItalic) {
+static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
+        jint givenWeight, jint givenItalic) {
+    uirenderer::FatVector<SkFontMgr::FontParameters::Axis, 2> skiaAxes;
+    for (const auto& axis : builder->axes) {
+        skiaAxes.emplace_back(SkFontMgr::FontParameters::Axis{axis.axisTag, axis.value});
+    }
+
+    const size_t fontSize = data->size();
+    const void* fontPtr = data->data();
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
+
+    SkFontMgr::FontParameters params;
+    params.setCollectionIndex(ttcIndex);
+    params.setAxes(skiaAxes.data(), skiaAxes.size());
+
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), params));
+    if (face == NULL) {
+        ALOGE("addFont failed to create font, invalid request");
+        builder->axes.clear();
+        return false;
+    }
     std::shared_ptr<minikin::MinikinFont> minikinFont =
-            std::make_shared<MinikinFontSkia>(std::move(face), fontData, fontSize, ttcIndex,
-                    std::vector<minikin::FontVariation>());
-    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
+                    builder->axes);
+
     int weight = givenWeight / 100;
-    bool italic = givenItalic;
-    if (weight == 0) {
-        if (!minikin::FontFamily::analyzeStyle(minikinFont, &weight, &italic)) {
+    bool italic = givenItalic == 1;
+    if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
+        int os2Weight;
+        bool os2Italic;
+        if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
             ALOGE("analyzeStyle failed. Using default style");
-            weight = 4;
-            italic = false;
+            os2Weight = 4;
+            os2Italic = false;
+        }
+        if (givenWeight == RESOLVE_BY_FONT_TABLE) {
+            weight = os2Weight;
+        }
+        if (givenItalic == RESOLVE_BY_FONT_TABLE) {
+            italic = os2Italic;
         }
     }
 
-    builder->fonts.push_back(minikin::Font(
-            std::move(minikinFont), minikin::FontStyle(weight, italic)));
+    builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
+    builder->axes.clear();
+    return true;
 }
 
 static void release_global_ref(const void* /*data*/, void* context) {
@@ -125,80 +158,47 @@
 }
 
 static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, jobject bytebuf,
-        jint ttcIndex) {
+        jint ttcIndex, jint weight, jint isItalic) {
     NPE_CHECK_RETURN_ZERO(env, bytebuf);
+    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
     const void* fontPtr = env->GetDirectBufferAddress(bytebuf);
     if (fontPtr == NULL) {
         ALOGE("addFont failed to create font, buffer invalid");
+        builder->axes.clear();
         return false;
     }
     jlong fontSize = env->GetDirectBufferCapacity(bytebuf);
     if (fontSize < 0) {
         ALOGE("addFont failed to create font, buffer size invalid");
+        builder->axes.clear();
         return false;
     }
     jobject fontRef = MakeGlobalRefOrDie(env, bytebuf);
     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
             release_global_ref, reinterpret_cast<void*>(fontRef)));
-    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
-    SkFontMgr::FontParameters params;
-    params.setCollectionIndex(ttcIndex);
-
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), params));
-    if (face == NULL) {
-        ALOGE("addFont failed to create font");
-        return false;
-    }
-    addSkTypeface(builderPtr, std::move(face), fontPtr, (size_t)fontSize, ttcIndex, 0, false);
-    return true;
+    return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
 }
 
 static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr,
-        jobject font, jint ttcIndex, jint weight, jboolean isItalic) {
+        jobject font, jint ttcIndex, jint weight, jint isItalic) {
     NPE_CHECK_RETURN_ZERO(env, font);
-
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-
-    // Declare axis native type.
-    std::vector<SkFontMgr::FontParameters::Axis> skiaAxes;
-    skiaAxes.reserve(builder->axes.size());
-    for (const minikin::FontVariation& minikinAxis : builder->axes) {
-        skiaAxes.push_back({minikinAxis.axisTag, minikinAxis.value});
-    }
-
     const void* fontPtr = env->GetDirectBufferAddress(font);
     if (fontPtr == NULL) {
         ALOGE("addFont failed to create font, buffer invalid");
+        builder->axes.clear();
         return false;
     }
     jlong fontSize = env->GetDirectBufferCapacity(font);
     if (fontSize < 0) {
         ALOGE("addFont failed to create font, buffer size invalid");
+        builder->axes.clear();
         return false;
     }
     jobject fontRef = MakeGlobalRefOrDie(env, font);
     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
             release_global_ref, reinterpret_cast<void*>(fontRef)));
-    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
-    SkFontMgr::FontParameters params;
-    params.setCollectionIndex(ttcIndex);
-    params.setAxes(skiaAxes.data(), skiaAxes.size());
-
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), params));
-    if (face == NULL) {
-        ALOGE("addFont failed to create font, invalid request");
-        return false;
-    }
-    std::shared_ptr<minikin::MinikinFont> minikinFont =
-            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
-                    std::vector<minikin::FontVariation>());
-    builder->fonts.push_back(minikin::Font(std::move(minikinFont),
-            minikin::FontStyle(weight / 100, isItalic)));
-    return true;
+    return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
 }
 
 static void releaseAsset(const void* ptr, void* context) {
@@ -206,18 +206,21 @@
 }
 
 static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong builderPtr,
-        jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset, jint weight,
-        jboolean isItalic) {
+        jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset, jint ttcIndex,
+        jint weight, jint isItalic) {
     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
+    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
     AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
     if (NULL == mgr) {
+        builder->axes.clear();
         return false;
     }
 
     ScopedUtfChars str(env, jpath);
     if (str.c_str() == nullptr) {
+        builder->axes.clear();
         return false;
     }
 
@@ -230,27 +233,19 @@
     }
 
     if (NULL == asset) {
+        builder->axes.clear();
         return false;
     }
 
     const void* buf = asset->getBuffer(false);
     if (NULL == buf) {
         delete asset;
+        builder->axes.clear();
         return false;
     }
 
-    size_t bufSize = asset->getLength();
     sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
-    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), SkFontMgr::FontParameters()));
-    if (face == NULL) {
-        ALOGE("addFontFromAsset failed to create font %s", str.c_str());
-        return false;
-    }
-
-    addSkTypeface(builderPtr, std::move(face), buf, bufSize, 0 /* ttc index */, weight, isItalic);
+    addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
     return true;
 }
 
@@ -266,10 +261,10 @@
     { "nCreateFamily",         "(J)J", (void*)FontFamily_create },
     { "nAbort",                "(J)V", (void*)FontFamily_abort },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
-    { "nAddFont",              "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont },
-    { "nAddFontWeightStyle",   "(JLjava/nio/ByteBuffer;IIZ)Z",
+    { "nAddFont",              "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont },
+    { "nAddFontWeightStyle",   "(JLjava/nio/ByteBuffer;III)Z",
             (void*)FontFamily_addFontWeightStyle },
-    { "nAddFontFromAssetManager",    "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIZ)Z",
+    { "nAddFontFromAssetManager",    "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIII)Z",
             (void*)FontFamily_addFontFromAssetManager },
     { "nAddAxisValue",         "(JIF)V", (void*)FontFamily_addAxisValue },
 };
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/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 58e4051..a3edf8d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -486,6 +486,7 @@
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+    <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
 
     <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -3606,6 +3607,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
     </application>
 
 </manifest>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4432e3c..3a1cf77 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4100,8 +4100,9 @@
     </declare-styleable>
 
     <declare-styleable name="ProgressBar">
+        <!-- Defines the minimum value. -->
         <attr name="min" format="integer" />
-        <!-- Defines the maximum value the progress can take. -->
+        <!-- Defines the maximum value. -->
         <attr name="max" format="integer" />
         <!-- Defines the default progress value, between 0 and max. -->
         <attr name="progress" format="integer" />
@@ -7009,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" />
@@ -7198,6 +7223,9 @@
         <!-- Whether the preference has enabled to have its view recycled when used in the list
              view. This is true by default. -->
         <attr name="recycleEnabled" format="boolean" />
+        <!-- Whether to use single line for the preference title text. By default, preference title
+             will be constrained to one line, so the default value of this attribute is true. -->
+        <attr name="singleLineTitle" format="boolean" />
     </declare-styleable>
 
     <!-- Base attributes available to CheckBoxPreference. -->
@@ -8565,6 +8593,7 @@
         <attr name="fontProviderAuthority" format="string" />
         <attr name="fontProviderPackage" format="string" />
         <attr name="fontProviderQuery" format="string" />
+        <attr name="fontProviderCerts" format="reference" />
     </declare-styleable>
 
     <!-- @hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cf6bd9e..b9409f2 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1422,7 +1422,7 @@
             <enum name="video" value="2" />
             <!-- Apps which primarily work with images or photos, such as camera or gallery apps. -->
             <enum name="image" value="3" />
-            <!-- Apps which are primarily social apps, such as messaging, communication, or social network apps. -->
+            <!-- Apps which are primarily social apps, such as messaging, communication, email, or social network apps. -->
             <enum name="social" value="4" />
             <!-- Apps which are primarily news apps, such as newspapers, magazines, or sports apps. -->
             <enum name="news" value="5" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 67a3aee..68e766e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2691,6 +2691,10 @@
     <!-- List of packages to enable in carrier demo mode (comma separated). -->
     <string name="config_carrierDemoModePackages" translatable="false"></string>
 
+    <!-- Number of days preloaded file cache should be preserved on a device before it can be
+         deleted -->
+    <integer name="config_keepPreloadsMinDays">7</integer>
+
     <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
     <bool name="config_useRoundIcon">false</bool>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f965c69..d6b5527 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2808,6 +2808,10 @@
         <public name="recycleEnabled"/>
         <public name="isStatic" />
         <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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a9a7116..d4db258 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -209,8 +209,7 @@
     <!-- Displayed to tell the user that they should switch their network preference. -->
     <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
     <!-- Displayed to tell the user that they should switch their network preference. -->
-    <string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at Settings > Cellular networks > Preferred network type."</string>
-
+    <string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at System &gt; Network &amp; Internet &gt; Mobile networks &gt; Preferred network type."</string>
 
     <!-- Displayed to tell the user that peer changed TTY mode -->
     <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
@@ -263,7 +262,7 @@
     <string-array name="wfcOperatorErrorNotificationMessages">
         <item>Register with your carrier</item>
     </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
+    <!-- Template for showing mobile network operator name while WFC is active -->
     <string-array name="wfcSpnFormats">
         <item>%s</item>
         <item>%s Wi-Fi Calling</item>
@@ -272,8 +271,8 @@
     <string name="wifi_calling_off_summary">Off</string>
     <!-- WFC, summary for Wi-Fi Preferred -->
     <string name="wfc_mode_wifi_preferred_summary">Wi-Fi preferred</string>
-    <!-- WFC, summary for Cellular Preferred -->
-    <string name="wfc_mode_cellular_preferred_summary">Cellular preferred</string>
+    <!-- WFC, summary for Mobile data Preferred -->
+    <string name="wfc_mode_cellular_preferred_summary">Mobile preferred</string>
     <!-- WFC, summary for Wi-Fi Only -->
     <string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
 
@@ -2972,18 +2971,18 @@
     <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
     <string name="wifi_no_internet_detailed">Tap for options</string>
 
-    <!-- A notification might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
+    <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
     <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
 
-    <!-- A notification might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
+    <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
     <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no Internet access. Charges may apply.</string>
 
-    <!-- A toast might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
+    <!-- A toast might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
     <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></string>
 
     <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
     <string-array name="network_switch_type_name">
-        <item>cellular data</item>
+        <item>mobile data</item>
         <item>Wi-Fi</item>
         <item>Bluetooth</item>
         <item>Ethernet</item>
@@ -3067,13 +3066,13 @@
     <!-- See SIM_REMOVED_DIALOG.  This is the title of that dialog. -->
     <string name="sim_removed_title">SIM card removed</string>
     <!-- See SIM_REMOVED_DIALOG.  This is the message of that dialog. -->
-    <string name="sim_removed_message">The cellular network will be unavailable until you restart with a valid SIM card inserted.</string>
+    <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM card inserted.</string>
     <!-- See SIM_REMOVED_DIALOG.  This is the button of that dialog. -->
     <string name="sim_done_button">Done</string>
     <!-- See SIM_ADDED_DIALOG.  This is the title of that dialog. -->
     <string name="sim_added_title">SIM card added</string>
     <!-- See SIM_ADDED_DIALOG.  This is the message of that dialog. -->
-    <string name="sim_added_message">Restart your device to access the cellular network.</string>
+    <string name="sim_added_message">Restart your device to access the mobile network.</string>
     <!-- See SIM_ADDED_DIALOG.  This is the button of that dialog. -->
     <string name="sim_restart_button">Restart</string>
     <!-- See Carrier_App_Dialog. This is the message of that dialog. -->
@@ -3628,7 +3627,7 @@
     <!-- Notification title when 4G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_4g_limit_title">4G data limit reached</string>
     <!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_mobile_limit_title">Cellular data limit reached</string>
+    <string name="data_usage_mobile_limit_title">Mobile data limit reached</string>
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_wifi_limit_title">Wi-Fi data limit reached</string>
     <!-- Notification body when data usage has exceeded limit threshold, and has been disabled. -->
@@ -3639,7 +3638,7 @@
     <!-- Notification title when 4G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_4g_limit_snoozed_title">4G data limit exceeded</string>
     <!-- Notification title when mobile data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
-    <string name="data_usage_mobile_limit_snoozed_title">Cellular data limit exceeded</string>
+    <string name="data_usage_mobile_limit_snoozed_title">Mobile data limit exceeded</string>
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_wifi_limit_snoozed_title">Wi-Fi data limit exceeded</string>
     <!-- Notification body when data usage has exceeded limit threshold. -->
@@ -4538,7 +4537,7 @@
     <string name="app_category_video">Movies &amp; Video</string>
     <!-- Category title for apps which primarily work with images or photos, such as camera or gallery apps. [CHAR LIMIT=32] -->
     <string name="app_category_image">Photos &amp; Images</string>
-    <!-- Category title for apps which are primarily social apps, such as messaging, communication, or social network apps. [CHAR LIMIT=32] -->
+    <!-- Category title for apps which are primarily social apps, such as messaging, communication, email, or social network apps. [CHAR LIMIT=32] -->
     <string name="app_category_social">Social &amp; Communication</string>
     <!-- Category title for apps which are primarily news apps, such as newspapers, magazines, or sports apps. [CHAR LIMIT=32] -->
     <string name="app_category_news">News &amp; Magazines</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f9fe333..4ef3922 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -421,6 +421,7 @@
   <java-symbol type="integer" name="config_valid_wappush_index" />
   <java-symbol type="integer" name="config_overrideHasPermanentMenuKey" />
   <java-symbol type="integer" name="config_mdc_initial_max_retry" />
+  <java-symbol type="integer" name="config_keepPreloadsMinDays" />
   <java-symbol type="bool" name="config_hasPermanentDpad" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
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/coretests/res/font/samplexmldownloadedfontmulticerts.xml b/core/tests/coretests/res/font/samplexmldownloadedfontmulticerts.xml
new file mode 100644
index 0000000..7a753c3
--- /dev/null
+++ b/core/tests/coretests/res/font/samplexmldownloadedfontmulticerts.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fontProviderAuthority="com.example.test.fontprovider"
+        android:fontProviderQuery="MyRequestedFont"
+        android:fontProviderPackage="com.example.test.fontprovider.package"
+        android:fontProviderCerts="@array/certarray">
+</font-family>
\ No newline at end of file
diff --git a/core/tests/coretests/res/font/samplexmldownloadedfontsinglecerts.xml b/core/tests/coretests/res/font/samplexmldownloadedfontsinglecerts.xml
new file mode 100644
index 0000000..b834771
--- /dev/null
+++ b/core/tests/coretests/res/font/samplexmldownloadedfontsinglecerts.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fontProviderAuthority="com.example.test.fontprovider"
+        android:fontProviderQuery="MyRequestedFont"
+        android:fontProviderPackage="com.example.test.fontprovider.package"
+        android:fontProviderCerts="@array/certs1">
+</font-family>
\ No newline at end of file
diff --git a/core/tests/coretests/res/values/arrays.xml b/core/tests/coretests/res/values/arrays.xml
index f76da85..7a25707 100644
--- a/core/tests/coretests/res/values/arrays.xml
+++ b/core/tests/coretests/res/values/arrays.xml
@@ -31,4 +31,19 @@
         <item>2 days</item>
         <item>1 week</item>
     </string-array>
+
+    <string-array name="certs1">
+        <item>123456789</item>
+        <item>987654321</item>
+    </string-array>
+
+    <string-array name="certs2">
+        <item>abcdefg</item>
+        <item>gfedcba</item>
+    </string-array>
+
+    <array name="certarray">
+        <item>@array/certs1</item>
+        <item>@array/certs2</item>
+    </array>
 </resources>
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 82f4690..5e426e8 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -15,21 +15,20 @@
  */
 package android.content.res;
 
-import static junit.framework.Assert.assertNull;
+import static android.content.res.FontResourcesParser.FamilyResourceEntry;
+import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
+import static android.content.res.FontResourcesParser.FontFileResourceEntry;
+import static android.content.res.FontResourcesParser.ProviderResourceEntry;
+
+import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import static android.content.res.FontResourcesParser.FamilyResourceEntry;
-import static android.content.res.FontResourcesParser.ProviderResourceEntry;
-import static android.content.res.FontResourcesParser.FontFileResourceEntry;
-import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
-
 import android.app.Instrumentation;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.text.FontConfig;
 
 import com.android.frameworks.coretests.R;
 
@@ -97,4 +96,50 @@
         assertEquals("com.example.test.fontprovider.package", providerEntry.getPackage());
         assertEquals("MyRequestedFont", providerEntry.getQuery());
     }
+
+    @Test
+    public void testParseDownloadableFont_singleCerts() throws IOException, XmlPullParserException {
+        XmlResourceParser parser = mResources.getXml(R.font.samplexmldownloadedfontsinglecerts);
+
+        FamilyResourceEntry result = FontResourcesParser.parse(parser, mResources);
+
+        assertNotNull(result);
+        assertTrue(result instanceof ProviderResourceEntry);
+        ProviderResourceEntry providerResourceEntry = (ProviderResourceEntry) result;
+        assertEquals("com.example.test.fontprovider", providerResourceEntry.getAuthority());
+        assertEquals("MyRequestedFont", providerResourceEntry.getQuery());
+        assertEquals("com.example.test.fontprovider.package", providerResourceEntry.getPackage());
+        List<List<String>> certList = providerResourceEntry.getCerts();
+        assertNotNull(certList);
+        assertEquals(1, certList.size());
+        List<String> certs = certList.get(0);
+        assertEquals(2, certs.size());
+        assertEquals("123456789", certs.get(0));
+        assertEquals("987654321", certs.get(1));
+    }
+
+    @Test
+    public void testParseDownloadableFont_multipleCerts() throws IOException, XmlPullParserException {
+        XmlResourceParser parser = mResources.getXml(R.font.samplexmldownloadedfontmulticerts);
+
+        FamilyResourceEntry result = FontResourcesParser.parse(parser, mResources);
+
+        assertNotNull(result);
+        assertTrue(result instanceof ProviderResourceEntry);
+        ProviderResourceEntry providerResourceEntry = (ProviderResourceEntry) result;
+        assertEquals("com.example.test.fontprovider", providerResourceEntry.getAuthority());
+        assertEquals("MyRequestedFont", providerResourceEntry.getQuery());
+        assertEquals("com.example.test.fontprovider.package", providerResourceEntry.getPackage());
+        List<List<String>> certList = providerResourceEntry.getCerts();
+        assertNotNull(certList);
+        assertEquals(2, certList.size());
+        List<String> certs1 = certList.get(0);
+        assertEquals(2, certs1.size());
+        assertEquals("123456789", certs1.get(0));
+        assertEquals("987654321", certs1.get(1));
+        List<String> certs2 = certList.get(1);
+        assertEquals(2, certs2.size());
+        assertEquals("abcdefg", certs2.get(0));
+        assertEquals("gfedcba", certs2.get(1));
+    }
 }
diff --git a/core/tests/coretests/src/android/database/PageViewCursorTest.java b/core/tests/coretests/src/android/database/PageViewCursorTest.java
index 0be89d5..62b5410 100644
--- a/core/tests/coretests/src/android/database/PageViewCursorTest.java
+++ b/core/tests/coretests/src/android/database/PageViewCursorTest.java
@@ -19,15 +19,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.os.Bundle;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-import android.util.MathUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -259,12 +253,19 @@
     }
 
     @Test
-    public void testPagingMarker() {
+    public void testAutoPagedExtra() {
         mCursor = new PageViewCursor(mDelegate, 5, 100);
         assertTrue(mCursor.getExtras().getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
     }
 
     @Test
+    public void testGetWindow() {
+        mCursor = new PageViewCursor(mDelegate, 5, 5);
+        CursorWindow window = mCursor.getWindow();
+        assertEquals(5, window.getNumRows());
+    }
+
+    @Test
     public void testWrap() {
         Bundle queryArgs = new Bundle();
         queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
diff --git a/core/tests/coretests/src/android/graphics/VariationParserTest.java b/core/tests/coretests/src/android/graphics/VariationParserTest.java
index a2ead40..fdabb13 100644
--- a/core/tests/coretests/src/android/graphics/VariationParserTest.java
+++ b/core/tests/coretests/src/android/graphics/VariationParserTest.java
@@ -28,7 +28,7 @@
 
     @SmallTest
     public void testParseFontVariationSetting() {
-        int tag = FontListParser.makeTag('w', 'd', 't', 'h');
+        int tag = FontListParser.makeTag("wdth");
         List<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings("'wdth' 1");
         assertEquals(tag, axes.get(0).getTag());
         assertEquals(1.0f, axes.get(0).getStyleValue());
@@ -45,7 +45,7 @@
         assertEquals(tag, axes.get(0).getTag());
         assertEquals(0.5f, axes.get(0).getStyleValue());
 
-        tag = FontListParser.makeTag('A', 'X', ' ', ' ');
+        tag = FontListParser.makeTag("AX  ");
         axes = FontListParser.parseFontVariationSettings("'AX  ' 1");
         assertEquals(tag, axes.get(0).getTag());
         assertEquals(1.0f, axes.get(0).getStyleValue());
@@ -93,8 +93,8 @@
     public void testParseFontVariationStyleSettings() {
         List<FontConfig.Axis> axes =
                 FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
-        int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
-        int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
+        int tag1 = FontListParser.makeTag("wdth");
+        int tag2 = FontListParser.makeTag("AX  ");
         assertEquals(tag1, axes.get(0).getTag());
         assertEquals(10.0f, axes.get(0).getStyleValue());
         assertEquals(tag2, axes.get(1).getTag());
@@ -102,7 +102,7 @@
 
         // Test only spacers are allowed before tag
         axes = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
-        tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
+        tag1 = FontListParser.makeTag("wdth");
         assertEquals(tag1, axes.get(0).getTag());
         assertEquals(10.0f, axes.get(0).getStyleValue());
         assertEquals(1, axes.size());
@@ -119,8 +119,8 @@
 
     @SmallTest
     public void testMakeTag() {
-      assertEquals(0x77647468, FontListParser.makeTag('w', 'd', 't', 'h'));
-      assertEquals(0x41582020, FontListParser.makeTag('A', 'X', ' ', ' '));
-      assertEquals(0x20202020, FontListParser.makeTag(' ', ' ', ' ', ' '));
+      assertEquals(0x77647468, FontListParser.makeTag("wdth"));
+      assertEquals(0x41582020, FontListParser.makeTag("AX  "));
+      assertEquals(0x20202020, FontListParser.makeTag("    "));
     }
 }
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 7a4980a..56e977c 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -109,7 +109,7 @@
     }
 
     public static String expectedSchedulerGroup(int prio) {
-        return prio < Process.THREAD_PRIORITY_BACKGROUND ? "/" : "/bg_non_interactive";
+        return "/";
     }
 
     public void testPassPriorityToService() throws Exception {
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
index d90fc2b..6820e92 100644
--- a/core/tests/coretests/src/android/provider/FontsContractTest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -51,6 +51,11 @@
 public class FontsContractTest extends ProviderTestCase2<TestFontsProvider> {
     private static final byte[] BYTE_ARRAY =
             Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
+    // Use a different instance to test byte array comparison
+    private static final byte[] BYTE_ARRAY_COPY =
+            Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
+    private static final byte[] BYTE_ARRAY_2 =
+            Base64.decode("e04fd020ea3a6910a2d808002b32", Base64.DEFAULT);
     private static final String PACKAGE_NAME = "com.my.font.provider.package";
 
     private final FontRequest request = new FontRequest(
@@ -268,6 +273,34 @@
         assertNull(result);
     }
 
+    public void testGetProvider_providerIsNonSystemAppDuplicateCerts()
+            throws PackageManager.NameNotFoundException {
+        ProviderInfo info = new ProviderInfo();
+        info.packageName = PACKAGE_NAME;
+        info.applicationInfo = new ApplicationInfo();
+        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
+        PackageInfo packageInfo = new PackageInfo();
+        Signature signature = mock(Signature.class);
+        when(signature.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
+        Signature signature2 = mock(Signature.class);
+        when(signature2.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
+        packageInfo.packageName = PACKAGE_NAME;
+        packageInfo.signatures = new Signature[] { signature, signature2 };
+        when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
+
+        // The provider has {BYTE_ARRAY_COPY, BYTE_ARRAY_COPY}, the request has
+        // {BYTE_ARRAY_2, BYTE_ARRAY_COPY}.
+        List<byte[]> certList = Arrays.asList(BYTE_ARRAY_2, BYTE_ARRAY_COPY);
+        FontRequest requestRightCerts = new FontRequest(
+                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+        ProviderInfo result = mContract.getProvider(requestRightCerts, mResultReceiver);
+
+        // The given list includes an extra cert and doesn't have a second copy of the cert like
+        // the provider does, so it should have failed.
+        verify(mResultReceiver).send(FontsContract.RESULT_CODE_WRONG_CERTIFICATES, null);
+        assertNull(result);
+    }
+
     public void testGetProvider_providerIsNonSystemAppCorrectCertsSeveralSets()
             throws PackageManager.NameNotFoundException {
         ProviderInfo info = setupPackageManager();
@@ -306,7 +339,7 @@
         when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
         PackageInfo packageInfo = new PackageInfo();
         Signature signature = mock(Signature.class);
-        when(signature.toByteArray()).thenReturn(BYTE_ARRAY);
+        when(signature.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
         packageInfo.packageName = PACKAGE_NAME;
         packageInfo.signatures = new Signature[] { signature };
         when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 77a1035..bc1d88b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -254,6 +254,7 @@
         <permission name="android.permission.BIND_APPWIDGET"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
+        <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
         <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
         <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
         <permission name="android.permission.DELETE_CACHE_FILES"/>
@@ -339,6 +340,14 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.tv">
+        <permission name="android.permission.DVB_DEVICE" />
+        <permission name="android.permission.GLOBAL_SEARCH" />
+        <permission name="android.permission.MODIFY_PARENTAL_CONTROLS" />
+        <permission name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" />
+        <permission name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.vpndialogs">
         <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
         <permission name="android.permission.CONTROL_VPN"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 2ebd2cc..1f339f7 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -48,6 +48,7 @@
      */
     protected int mScreenDensity = Bitmap.DENSITY_NONE;
     protected int mDensity = Bitmap.DENSITY_NONE;
+    private boolean mAllowHwBitmapsInSwMode = false;
 
     protected void throwIfCannotDraw(Bitmap bitmap) {
         if (bitmap.isRecycled()) {
@@ -511,8 +512,23 @@
                 indices, indexOffset, indexCount, paint.getNativeInstance());
     }
 
+    /**
+     * @hide
+     */
+    public void setHwBitmapsInSwModeEnabled(boolean enabled) {
+        mAllowHwBitmapsInSwMode = enabled;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isHwBitmapsInSwModeEnabled() {
+        return mAllowHwBitmapsInSwMode;
+    }
+
     private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
-        if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
+        if (!mAllowHwBitmapsInSwMode && !isHardwareAccelerated()
+                && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
             throw new IllegalStateException("Software rendering doesn't support hardware bitmaps");
         }
     }
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 16fc2b1..6214ba6 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -81,7 +81,8 @@
         }
     }
 
-    public boolean addFont(String path, int ttcIndex) {
+    public boolean addFont(String path, int ttcIndex, FontConfig.Axis[] axes, int weight,
+            int italic) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFont after freezing.");
         }
@@ -89,22 +90,29 @@
             FileChannel fileChannel = file.getChannel();
             long fontSize = fileChannel.size();
             ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-            return nAddFont(mBuilderPtr, fontBuffer, ttcIndex);
+            if (axes != null) {
+                for (FontConfig.Axis axis : axes) {
+                    nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+                }
+            }
+            return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic);
         } catch (IOException e) {
             Log.e(TAG, "Error mapping font file " + path);
             return false;
         }
     }
 
-    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, FontConfig.Axis[] axes,
-            int weight, boolean style) {
+    public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontConfig.Axis[] axes,
+            int weight, int italic) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFontWeightStyle after freezing.");
         }
-        for (FontConfig.Axis axis : axes) {
-            nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+        if (axes != null) {
+            for (FontConfig.Axis axis : axes) {
+                nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+            }
         }
-        return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, style);
+        return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, italic);
     }
 
     /**
@@ -120,11 +128,23 @@
      * @return
      */
     public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
-            boolean isAsset, int weight, boolean isItalic) {
+            boolean isAsset, int ttcIndex, int weight, int isItalic,
+            FontConfig.Axis[] axes) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFontFromAsset after freezing.");
         }
-        return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, weight, isItalic);
+        if (axes != null) {
+            for (FontConfig.Axis axis : axes) {
+                nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+            }
+        }
+        return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, ttcIndex, weight,
+                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);
@@ -137,11 +157,14 @@
 
     @CriticalNative
     private static native void nUnrefFamily(long nativePtr);
-    private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex);
+    // By passing -1 to weigth argument, the weight value is resolved by OS/2 table in the font.
+    // By passing -1 to italic argument, the italic value is resolved by OS/2 table in the font.
+    private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex,
+            int weight, int isItalic);
     private static native boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, int weight, boolean isItalic);
+            int ttcIndex, int weight, int isItalic);
     private static native boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr,
-            String path, int cookie, boolean isAsset, int weight, boolean isItalic);
+            String path, int cookie, boolean isAsset, int ttcIndex, int weight, int isItalic);
 
     // The added axis values are only valid for the next nAddFont* method call.
     @CriticalNative
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 1b6969f..b78df34 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -98,15 +98,17 @@
             } catch (NumberFormatException e) {
                 continue;  // ignoreing invalid number format
             }
-            int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
-                    tagString.charAt(3));
+            int tag = makeTag(tagString);
             axisList.add(new FontConfig.Axis(tag, styleValue));
         }
         return axisList;
     }
 
-    @VisibleForTesting
-    public static int makeTag(char c1, char c2, char c3, char c4) {
+    public static int makeTag(String tagString) {
+        char c1 = tagString.charAt(0);
+        char c2 = tagString.charAt(1);
+        char c3 = tagString.charAt(2);
+        char c4 = tagString.charAt(3);
         return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
     }
 
@@ -198,6 +200,13 @@
      */
     private static final Pattern TAG_PATTERN = Pattern.compile("[\\x20-\\x7E]{4}");
 
+    public static boolean isValidTag(String tagString) {
+        if (tagString == null || tagString.length() != 4) {
+            return false;
+        }
+        return TAG_PATTERN.matcher(tagString).matches();
+    }
+
     /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
      *  '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
      */
@@ -208,8 +217,8 @@
             throws XmlPullParserException, IOException {
         int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
-        if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
-            tag = makeTag(tagStr.charAt(0), tagStr.charAt(1), tagStr.charAt(2), tagStr.charAt(3));
+        if (isValidTag(tagStr)) {
+            tag = makeTag(tagStr);
         } else {
             throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
         }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 8511c1f..042bac6 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -21,11 +21,15 @@
 import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.AssetManager;
+import android.graphics.FontListParser;
 import android.graphics.fonts.FontRequest;
 import android.graphics.fonts.FontResult;
 import android.os.Bundle;
@@ -34,18 +38,21 @@
 import android.os.ResultReceiver;
 import android.provider.FontsContract;
 import android.text.FontConfig;
+import android.util.Base64;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.LruCache;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -55,9 +62,12 @@
 import java.nio.channels.FileChannel;
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * The Typeface class specifies the typeface and intrinsic style of a font.
@@ -148,13 +158,16 @@
     public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
         if (sFallbackFonts != null) {
             synchronized (sDynamicTypefaceCache) {
-                final String key = createAssetUid(mgr, path);
+                final String key = Builder.createAssetUid(
+                        mgr, path, 0 /* ttcIndex */, null /* axes */);
                 Typeface typeface = sDynamicTypefaceCache.get(key);
                 if (typeface != null) return typeface;
 
                 FontFamily fontFamily = new FontFamily();
+                // TODO: introduce ttc index and variation settings to resource type font.
                 if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */,
-                        0 /* use OS/2 table to determine weight and italic */, false)) {
+                        0 /* ttcIndex */, Builder.RESOLVE_BY_FONT_TABLE /* weight */,
+                        Builder.RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
                     fontFamily.freeze();
                     FontFamily[] families = {fontFamily};
                     typeface = createFromFamiliesWithDefault(families);
@@ -184,10 +197,22 @@
                 if (typeface != null) {
                     return typeface;
                 }
+                List<List<String>> givenCerts = providerEntry.getCerts();
+                List<List<byte[]>> certs = new ArrayList<>();
+                if (givenCerts != null) {
+                    for (int i = 0; i < givenCerts.size(); i++) {
+                        List<String> certSet = givenCerts.get(i);
+                        List<byte[]> byteArraySet = new ArrayList<>();
+                        for (int j = 0; j < certSet.size(); j++) {
+                            byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT));
+                        }
+                        certs.add(byteArraySet);
+                    }
+                }
                 // Downloaded font and it wasn't cached, request it again and return a
                 // default font instead (nothing we can do now).
                 create(new FontRequest(providerEntry.getAuthority(), providerEntry.getPackage(),
-                        providerEntry.getQuery()), NO_OP_REQUEST_CALLBACK);
+                        providerEntry.getQuery(), certs), NO_OP_REQUEST_CALLBACK);
                 return DEFAULT;
             }
 
@@ -198,8 +223,10 @@
             FontFamily fontFamily = new FontFamily();
             for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
                 if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
-                        0 /* resourceCookie */, false /* isAsset */, fontFile.getWeight(),
-                      fontFile.isItalic())) {
+                        0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
+                        fontFile.getWeight(),
+                        fontFile.isItalic() ? Builder.ITALIC : Builder.NORMAL,
+                        null /* axes */)) {
                     return null;
                 }
             }
@@ -207,7 +234,8 @@
             FontFamily[] familyChain = { fontFamily };
             typeface = createFromFamiliesWithDefault(familyChain);
             synchronized (sDynamicTypefaceCache) {
-                final String key = createAssetUid(mgr, path);
+                final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
+                        null /* axes */);
                 sDynamicTypefaceCache.put(key, typeface);
             }
             return typeface;
@@ -221,7 +249,7 @@
      */
     public static Typeface findFromCache(AssetManager mgr, String path) {
         synchronized (sDynamicTypefaceCache) {
-            final String key = createAssetUid(mgr, path);
+            final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */);
             Typeface typeface = sDynamicTypefaceCache.get(key);
             if (typeface != null) {
                 return typeface;
@@ -332,8 +360,9 @@
                 int weight = (style & BOLD) != 0 ? 700 : 400;
                 // TODO: this method should be
                 // create(fd, ttcIndex, fontVariationSettings, style).
-                if (!fontFamily.addFontWeightStyle(fontBuffer, result.getTtcIndex(),
-                                null, weight, (style & ITALIC) != 0)) {
+                if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(),
+                                null, weight,
+                                (style & ITALIC) == 0 ? Builder.NORMAL : Builder.ITALIC)) {
                     Log.e(TAG, "Error creating font " + request.getQuery());
                     callback.onTypefaceRequestFailed(
                             FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
@@ -432,6 +461,346 @@
     };
 
     /**
+     * A builder class for creating new Typeface instance.
+     *
+     * Examples,
+     * 1) Create Typeface from ttf file.
+     * <pre>
+     * <code>
+     * Typeface.Builder buidler = new Typeface.Builder.obtain();
+     * builder.setSourceFromFilePath("your_font_file.ttf");
+     * Typeface typeface = builder.build();
+     * builder.recycle();
+     * </code>
+     * </pre>
+     *
+     * 2) Create Typeface from ttc file in assets directory.
+     * <pre>
+     * <code>
+     * Typeface.Builder buidler = new Typeface.Builder.obtain();
+     * builder.setSourceFromAsset(getAssets(), "your_font_file.ttc");
+     * builder.setTtcIndex(2);  // set index of font collection.
+     * Typeface typeface = builder.build();
+     * builder.recycle();
+     * </code>
+     * </pre>
+     *
+     * 3) Create Typeface from existing Typeface with variation settings.
+     * <pre>
+     *
+     * <p>Note that only one source can be specified for the single Typeface.</p>
+     */
+    public static final class Builder {
+        /**
+         * Value for weight and italic.
+         *
+         * Indicates the value is resolved by font metadata.
+         */
+        // Must be same with C++ constant in core/jni/android/graphics/FontFamily.cpp
+        public static final int RESOLVE_BY_FONT_TABLE = -1;
+
+        /**
+         * Value for italic.
+         *
+         * Indicates the font style is not italic.
+         */
+        public static final int NORMAL = 0;
+
+        /**
+         * Value for italic.
+         *
+         * Indicates the font style is italic.
+         */
+        public static final int ITALIC = 1;
+
+        private int mTtcIndex;
+        private FontConfig.Axis[] mAxes;
+
+        private AssetManager mAssetManager;
+        private String mPath;
+        private FileDescriptor mFd;
+        private @IntRange(from = -1) int mWeight = RESOLVE_BY_FONT_TABLE;
+
+        /** @hide */
+        @Retention(SOURCE)
+        @IntDef({RESOLVE_BY_FONT_TABLE, NORMAL, ITALIC})
+        public @interface Italic {}
+        private @Italic int mItalic = RESOLVE_BY_FONT_TABLE;
+
+        private boolean mHasSourceSet = false;
+        private boolean mRecycled = false;
+
+        /** Use Builder.obtain() instead */
+        private void Builder() {}
+
+        private static AtomicReference<Builder> mCache = new AtomicReference<>();
+
+        /**
+         * Returns Typeface.Builder from pool.
+         */
+        public static Builder obtain() {
+            final Builder builder = mCache.getAndSet(null);
+            if (builder != null) {
+                builder.mRecycled = false;
+                return builder;
+            }
+            return new Builder();
+        }
+
+        /**
+         * Resets the internal states.
+         */
+        public void reset() {
+            checkNotRecycled();
+            mTtcIndex = 0;
+            mAxes = null;
+
+            mAssetManager = null;
+            mPath = null;
+            mFd = null;
+
+            mWeight = RESOLVE_BY_FONT_TABLE;
+            mItalic = RESOLVE_BY_FONT_TABLE;
+
+            mHasSourceSet = false;
+        }
+
+        /**
+         * Returns the instance to the pool.
+         */
+        public void recycle() {
+            reset();
+            mRecycled = true;
+
+            mCache.compareAndSet(null, this);
+        }
+
+        private void checkNotRecycled() {
+            if (mRecycled) {
+                throw new IllegalStateException("Don't use Builder after calling recycle()");
+            }
+        }
+
+        private void checkSingleFontSource() {
+            if (mHasSourceSet) {
+                throw new IllegalStateException("Typeface can only built with single font source.");
+            }
+        }
+
+        /**
+         * Sets a font file as a source of Typeface.
+         *
+         * @param path The file object refers to the font file.
+         */
+        public Builder setSourceFromFile(@NonNull File path) {
+            return setSourceFromFilePath(path.getAbsolutePath());
+        }
+
+        /**
+         * Sets a font file as a source of Typeface.
+         *
+         * @param fd The file descriptor. The passed fd must be mmap-able.
+         */
+        public Builder setSourceFromFile(@NonNull FileDescriptor fd) {
+            checkNotRecycled();
+            checkSingleFontSource();
+            mFd = fd;
+            mHasSourceSet = true;
+            return this;
+        }
+
+        /**
+         * Sets a font file as a source of Typeface.
+         *
+         * @param path The full path to the font file.
+         */
+        public Builder setSourceFromFilePath(@NonNull String path) {
+            checkNotRecycled();
+            checkSingleFontSource();
+            mPath = path;
+            mHasSourceSet = true;
+            return this;
+        }
+
+        /**
+         * Sets an asset entry as a source of Typeface.
+         *
+         * @param assetManager The application's asset manager
+         * @param path The file name of the font data in the asset directory
+         */
+        public Builder setSourceFromAsset(@NonNull AssetManager assetManager,
+                @NonNull String path) {
+            checkNotRecycled();
+            checkSingleFontSource();
+            mAssetManager = Preconditions.checkNotNull(assetManager);
+            mPath = Preconditions.checkStringNotEmpty(path);
+            mHasSourceSet = true;
+            return this;
+        }
+
+        /**
+         * Sets weight of the font.
+         *
+         * By passing {@link #RESOLVE_BY_FONT_TABLE}, weight value is resolved by OS/2 table in
+         * font file if possible.
+         * @param weight a weight value or {@link #RESOLVE_BY_FONT_TABLE}
+         */
+        public Builder setWeight(@IntRange(from = -1) int weight) {
+            checkNotRecycled();
+            mWeight = weight;
+            return this;
+        }
+
+        /**
+         * Sets italic information of the font.
+         *
+         * By passing {@link #RESOLVE_BY_FONT_TABLE}, italic or normal is determined by OS/2 table
+         * in font file if possible.
+         * @param italic One of {@link #NORMAL}, {@link #ITALIC}, {@link #RESOLVE_BY_FONT_TABLE}.
+         *                 will be used.
+         */
+        public Builder setItalic(@Italic int italic) {
+            checkNotRecycled();
+            mItalic = italic;
+            return this;
+        }
+
+        /**
+         * Sets an idex of the font collection.
+         *
+         * Can not be used for Typeface source. build() method will return null for invalid index.
+         * @param ttcIndex An index of the font collection. If the font source is not font
+         *                 collection, do not call this method or specify 0.
+         */
+        public Builder setTtcIndex(@IntRange(from = 0) int ttcIndex) {
+            checkNotRecycled();
+            mTtcIndex = ttcIndex;
+            return this;
+        }
+
+        /**
+         * Sets a font variation settings.
+         *
+         * @param variationSettings See {@link android.widget.TextView#setFontVariationSettings}.
+         */
+        public Builder setFontVariationSettings(@Nullable String variationSettings) {
+            checkNotRecycled();
+            if (mAxes != null) {
+                throw new IllegalStateException("Font variation settings are already set.");
+            }
+            final List<FontConfig.Axis> axesList = FontListParser.parseFontVariationSettings(
+                    variationSettings);
+            mAxes = axesList.toArray(new FontConfig.Axis[axesList.size()]);
+            return this;
+        }
+
+        /**
+         * Sets a font variation settings.
+         *
+         * @param axes An array of font variation axis tag-value pairs.
+         */
+        public Builder setFontVariationSettings(@Nullable FontConfig.Axis[] axes) {
+            checkNotRecycled();
+            if (mAxes != null) {
+                throw new IllegalStateException("Font variation settings are already set.");
+            }
+            mAxes = axes;
+            return this;
+        }
+
+        /**
+         * Creates a unique id for a given AssetManager and asset path.
+         *
+         * @param mgr  AssetManager instance
+         * @param path The path for the asset.
+         * @param ttcIndex The TTC index for the font.
+         * @param axes The font variation settings.
+         * @return Unique id for a given AssetManager and asset path.
+         */
+        private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex,
+                @Nullable FontConfig.Axis[] axes) {
+            final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
+            final StringBuilder builder = new StringBuilder();
+            final int size = pkgs.size();
+            for (int i = 0; i < size; i++) {
+                builder.append(pkgs.valueAt(i));
+                builder.append("-");
+            }
+            builder.append(path);
+            builder.append("-");
+            builder.append(Integer.toString(ttcIndex));
+            builder.append("-");
+            if (axes != null) {
+                for (FontConfig.Axis axis : axes) {
+                    builder.append(Integer.toHexString(axis.getTag()));
+                    builder.append("-");
+                    builder.append(Float.toString(axis.getStyleValue()));
+                }
+            }
+            return builder.toString();
+        }
+
+        /**
+         * Generates new Typeface from specified configuration.
+         *
+         * @return Newly created Typeface. May return null if some parameters are invalid.
+         */
+        public Typeface build() {
+            checkNotRecycled();
+            if (!mHasSourceSet) {
+                return null;
+            }
+
+            if (mFd != null) {  // set source by setSourceFromFile(FileDescriptor)
+                try (FileInputStream fis = new FileInputStream(mFd)) {
+                    FileChannel channel = fis.getChannel();
+                    long size = channel.size();
+                    ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
+
+                    final FontFamily fontFamily = new FontFamily();
+                    if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) {
+                        fontFamily.abortCreation();
+                        return null;
+                    }
+                    fontFamily.freeze();
+                    FontFamily[] families = { fontFamily };
+                    return createFromFamiliesWithDefault(families);
+                } catch (IOException e) {
+                    return null;
+                }
+            } else if (mAssetManager != null) {  // set source by setSourceFromAsset()
+                final String key = createAssetUid(mAssetManager, mPath, mTtcIndex, mAxes);
+                synchronized (sDynamicTypefaceCache) {
+                    Typeface typeface = sDynamicTypefaceCache.get(key);
+                    if (typeface != null) return typeface;
+                    final FontFamily fontFamily = new FontFamily();
+                    if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex,
+                            true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) {
+                        fontFamily.abortCreation();
+                        return null;
+                    }
+                    fontFamily.freeze();
+                    FontFamily[] families = { fontFamily };
+                    typeface = createFromFamiliesWithDefault(families);
+                    sDynamicTypefaceCache.put(key, typeface);
+                    return typeface;
+                }
+            } else if (mPath != null) {  // set source by setSourceFromFile(File)
+                final FontFamily fontFamily = new FontFamily();
+                if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) {
+                    fontFamily.abortCreation();
+                    return null;
+                }
+                fontFamily.freeze();
+                FontFamily[] families = { fontFamily };
+                return createFromFamiliesWithDefault(families);
+            } else {
+                throw new IllegalArgumentException("No source was set.");
+            }
+        }
+    }
+
+    /**
      * Create a typeface object given a family name, and option style information.
      * If null is passed for the name, then the "default" font will be chosen.
      * The resulting typeface object can be queried (getStyle()) to discover what
@@ -518,49 +887,26 @@
      * @return The new typeface.
      */
     public static Typeface createFromAsset(AssetManager mgr, String path) {
+        if (path == null) {
+            throw new NullPointerException();  // for backward compatibility
+        }
         if (sFallbackFonts != null) {
-            synchronized (sDynamicTypefaceCache) {
-                final String key = createAssetUid(mgr, path);
-                Typeface typeface = sDynamicTypefaceCache.get(key);
-                if (typeface != null) return typeface;
-
-                FontFamily fontFamily = new FontFamily();
-                if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */,
-                        0 /* use OS/2 table to determine weight and italic */, false)) {
-                    fontFamily.freeze();
-                    FontFamily[] families = { fontFamily };
-                    typeface = createFromFamiliesWithDefault(families);
-                    sDynamicTypefaceCache.put(key, typeface);
+            final Builder builder = Builder.obtain();
+            try {
+                builder.setSourceFromAsset(mgr, path);
+                Typeface typeface = builder.build();
+                if (typeface != null) {
                     return typeface;
-                } else {
-                    fontFamily.abortCreation();
                 }
+            } finally {
+                builder.recycle();
             }
         }
+        // For the compatibility reasons, throw runtime exception if failed to create Typeface.
         throw new RuntimeException("Font asset not found " + path);
     }
 
     /**
-     * Creates a unique id for a given AssetManager and asset path.
-     *
-     * @param mgr  AssetManager instance
-     * @param path The path for the asset.
-     * @return Unique id for a given AssetManager and asset path.
-     */
-    private static String createAssetUid(final AssetManager mgr, String path) {
-        final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
-        final StringBuilder builder = new StringBuilder();
-        builder.append("asset:");
-        final int size = pkgs.size();
-        for (int i = 0; i < size; i++) {
-            builder.append(pkgs.valueAt(i));
-            builder.append("-");
-        }
-        builder.append(path);
-        return builder.toString();
-    }
-
-    /**
      * Creates a unique id for a given font provider and query.
      */
     private static String createProviderUid(String authority, String query) {
@@ -578,7 +924,9 @@
      * @param path The path to the font data.
      * @return The new typeface.
      */
-    public static Typeface createFromFile(File path) {
+    public static Typeface createFromFile(@Nullable File path) {
+        // For the compatibility reasons, leaving possible NPE here.
+        // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileReferenceNull
         return createFromFile(path.getAbsolutePath());
     }
 
@@ -588,15 +936,24 @@
      * @param path The full path to the font data.
      * @return The new typeface.
      */
-    public static Typeface createFromFile(String path) {
+    public static Typeface createFromFile(@Nullable String path) {
+        if (path == null) {
+            // For the compatibility reasons, need to throw NPE if the argument is null.
+            // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileNameNull
+            throw new NullPointerException();
+        }
         if (sFallbackFonts != null) {
-            FontFamily fontFamily = new FontFamily();
-            if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
-                fontFamily.freeze();
-                FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families);
-            } else {
-                fontFamily.abortCreation();
+            final Builder builder = Builder.obtain();
+            try {
+                builder.setSourceFromFilePath(path);
+                Typeface typeface = builder.build();
+                if (typeface != null) {
+                    // For the compatibility reasons, throw runtime exception if failed to create
+                    // Typeface.
+                    return typeface;
+                }
+            } finally {
+                builder.recycle();
             }
         }
         throw new RuntimeException("Font not found " + path);
@@ -606,9 +963,8 @@
      * Create a new typeface from an array of font families.
      *
      * @param families array of font families
-     * @hide
      */
-    public static Typeface createFromFamilies(FontFamily[] families) {
+    private static Typeface createFromFamilies(FontFamily[] families) {
         long[] ptrArray = new long[families.length];
         for (int i = 0; i < families.length; i++) {
             ptrArray[i] = families[i].mNativePtr;
@@ -621,9 +977,8 @@
      * also the font families in the fallback list.
      *
      * @param families array of font families
-     * @hide
      */
-    public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
+    private static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
         long[] ptrArray = new long[families.length + sFallbackFonts.length];
         for (int i = 0; i < families.length; i++) {
             ptrArray[i] = families[i].mNativePtr;
@@ -660,8 +1015,8 @@
                     continue;
                 }
             }
-            if (!fontFamily.addFontWeightStyle(fontBuffer, font.getTtcIndex(), font.getAxes(),
-                    font.getWeight(), font.isItalic())) {
+            if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
+                    font.getWeight(), font.isItalic() ? Builder.ITALIC : Builder.NORMAL)) {
                 Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
             }
         }
@@ -806,6 +1161,7 @@
     }
 
     private static native long nativeCreateFromTypeface(long native_instance, int style);
+    // TODO: clean up: change List<FontConfig.Axis> to FontConfig.Axis[]
     private static native long nativeCreateFromTypefaceWithVariation(
             long native_instance, List<FontConfig.Axis> axes);
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
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/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 244c525..09840a5 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4430,6 +4430,7 @@
         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
             ALOGW("ResTable_map at %d is beyond type chunk data %d",
                  (int)curOff, dtohl(entry.type->header.size));
+            free(set);
             return BAD_TYPE;
         }
         map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
@@ -4442,6 +4443,7 @@
             if (grp->dynamicRefTable.lookupResourceId(&newName) != NO_ERROR) {
                 ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
                         (int) curOff, (int) newName);
+                free(set);
                 return UNKNOWN_ERROR;
             }
         }
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/src/com/android/settingslib/wifi/WifiTrackerFactory.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
new file mode 100644
index 0000000..d3bdeb7
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.settingslib.wifi;
+
+import android.content.Context;
+import android.os.Looper;
+
+/**
+ * Factory method used to inject WifiTracker instances.
+ */
+public class WifiTrackerFactory {
+    private static boolean sTestingMode = false;
+
+    private static WifiTracker sTestingWifiTracker;
+
+    public static void enableTestingMode() {
+        sTestingMode = true;
+    }
+
+    public static void disableTestingMode() {
+        sTestingMode = false;
+    }
+
+    public static void setTestingWifiTracker(WifiTracker tracker) {
+        sTestingWifiTracker = tracker;
+    }
+
+    public static WifiTracker create(
+            Context context, WifiTracker.WifiListener wifiListener, Looper workerLooper,
+            boolean includeSaved, boolean includeScans, boolean includePasspoints) {
+        if(sTestingMode) {
+            return sTestingWifiTracker;
+        }
+        return new WifiTracker(
+                context, wifiListener, workerLooper, includeSaved, includeScans, includePasspoints);
+    }
+}
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/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 3cce299..6bfab78 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -103,6 +103,7 @@
     <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
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/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1f58d4c..f8d1bfb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1582,7 +1582,7 @@
      */
     public void reportSimUnlocked(int subId) {
         if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")");
-        int slotId = SubscriptionManager.getSlotId(subId);
+        int slotId = SubscriptionManager.getSlotIndex(subId);
         handleSimStateChange(subId, slotId, State.READY);
     }
 
@@ -1751,7 +1751,7 @@
         for (int i = 0; i < list.size(); i++) {
             final SubscriptionInfo info = list.get(i);
             final int id = info.getSubscriptionId();
-            int slotId = SubscriptionManager.getSlotId(id);
+            int slotId = SubscriptionManager.getSlotIndex(id);
             if (state == getSimState(id) && bestSlotId > slotId ) {
                 resultId = id;
                 bestSlotId = slotId;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index bff1054..8580085 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/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index f53dad5..7162b31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -28,11 +28,11 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.widget.LinearLayout;
-
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -136,8 +136,14 @@
             return;
         }
 
-        mNavigationBarView = (CarNavigationBarView) View.inflate(mContext,
-                R.layout.car_navigation_bar, null);
+        // SystemUI requires that the navigation bar view have a parent. Since the regular
+        // StatusBar inflates navigation_bar_window as this parent view, use the same view for the
+        // CarNavigationBarView.
+        ViewGroup navigationBarWindow = (ViewGroup) View.inflate(mContext,
+                R.layout.navigation_bar_window, null);
+        View.inflate(mContext, R.layout.car_navigation_bar, navigationBarWindow);
+        mNavigationBarView = (CarNavigationBarView) navigationBarWindow.getChildAt(0);
+
         mController = new CarNavigationBarController(mContext, mNavigationBarView,
                 this /* ActivityStarter*/);
         mNavigationBarView.getBarTransitions().setAlwaysOpaque(true);
@@ -153,7 +159,8 @@
                 PixelFormat.TRANSLUCENT);
         lp.setTitle("CarNavigationBar");
         lp.windowAnimations = 0;
-        mWindowManager.addView(mNavigationBarView, lp);
+
+        mWindowManager.addView(navigationBarWindow, lp);
     }
 
     @Override
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/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index a8c8752..85eecdf 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -36,6 +36,8 @@
 import android.view.autofill.AutofillValue;
 import android.widget.ArrayAdapter;
 import android.widget.ListView;
+import android.widget.RemoteViews;
+
 import com.android.internal.R;
 import libcore.util.Objects;
 
@@ -110,15 +112,15 @@
                 final Dataset dataset = response.getDatasets().get(i);
                 final int index = dataset.getFieldIds().indexOf(focusedViewId);
                 if (index >= 0) {
-                    final AutofillValue value = dataset.getFieldValues().get(index);
+                    final RemoteViews presentation = dataset.getFieldPresentation(index);
                     final View view;
                     try {
-                        view = dataset.getPresentation().apply(context, null);
+                        view = presentation.apply(context, null);
                     } catch (RuntimeException e) {
                         Slog.e(TAG, "Error inflating remote views", e);
                         continue;
                     }
-
+                    final AutofillValue value = dataset.getFieldValues().get(index);
                     String valueText = null;
                     if (value.isText()) {
                         valueText = value.getTextValue().toString().toLowerCase();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8f2b428..30d06db 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1295,7 +1295,7 @@
         if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
 
         mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
-                mTransportBoundListener);
+                mTransportBoundListener, mHandlerThread.getLooper());
         mTransportManager.registerAllTransports();
 
         // Now that we know about valid backup participants, parse any
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 619ddb1..67f105e 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -27,9 +27,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -55,10 +59,15 @@
 
     private static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 
+    private static final long REBINDING_TIMEOUT_UNPROVISIONED_MS = 30 * 1000; // 30 sec
+    private static final long REBINDING_TIMEOUT_PROVISIONED_MS = 5 * 60 * 1000; // 5 mins
+    private static final int REBINDING_TIMEOUT_MSG = 1;
+
     private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final Set<ComponentName> mTransportWhitelist;
+    private final Handler mHandler;
 
     /**
      * This listener is called after we bind to any transport. If it returns true, this is a valid
@@ -83,12 +92,13 @@
     private final Map<String, ComponentName> mBoundTransports = new ArrayMap<>();
 
     TransportManager(Context context, Set<ComponentName> whitelist, String defaultTransport,
-            TransportBoundListener listener) {
+            TransportBoundListener listener, Looper looper) {
         mContext = context;
         mPackageManager = context.getPackageManager();
         mTransportWhitelist = (whitelist != null) ? whitelist : new ArraySet<>();
         mCurrentTransportName = defaultTransport;
         mTransportBoundListener = listener;
+        mHandler = new RebindOnTimeoutHandler(looper);
     }
 
     void onPackageAdded(String packageName) {
@@ -242,12 +252,12 @@
                 intent, 0, UserHandle.USER_SYSTEM);
         if (hosts != null) {
             for (ResolveInfo host : hosts) {
-                final ServiceInfo info = host.serviceInfo;
+                final ComponentName infoComponentName = host.serviceInfo.getComponentName();
                 boolean shouldBind = false;
                 if (components != null && packageName != null) {
                     for (String component : components) {
                         ComponentName cn = new ComponentName(pkgInfo.packageName, component);
-                        if (info.getComponentName().equals(cn)) {
+                        if (infoComponentName.equals(cn)) {
                             shouldBind = true;
                             break;
                         }
@@ -255,8 +265,8 @@
                 } else {
                     shouldBind = true;
                 }
-                if (shouldBind && isTransportTrusted(info.getComponentName())) {
-                    tryBindTransport(info);
+                if (shouldBind && isTransportTrusted(infoComponentName)) {
+                    tryBindTransport(infoComponentName);
                 }
             }
         }
@@ -283,8 +293,7 @@
         return true;
     }
 
-    private void tryBindTransport(ServiceInfo transport) {
-        final ComponentName transportComponentName = transport.getComponentName();
+    private void tryBindTransport(ComponentName transportComponentName) {
         Slog.d(TAG, "Binding to transport: " + transportComponentName.flattenToShortString());
         // TODO: b/22388012 (Multi user backup and restore)
         TransportConnection connection = new TransportConnection(transportComponentName);
@@ -335,17 +344,22 @@
                     success = false;
                     Slog.e(TAG, "Couldn't get transport name.", e);
                 } finally {
+                    // we need to intern() the String of the component, so that we can use it with
+                    // Handler's removeMessages(), which uses == operator to compare the tokens
+                    String componentShortString = component.flattenToShortString().intern();
                     if (success) {
-                        Slog.d(TAG, "Bound to transport: " + component.flattenToShortString());
+                        Slog.d(TAG, "Bound to transport: " + componentShortString);
                         mBoundTransports.put(mTransportName, component);
                         for (SelectBackupTransportCallback listener : mListeners) {
                             listener.onSuccess(mTransportName);
                         }
+                        // cancel rebinding on timeout for this component as we've already connected
+                        mHandler.removeMessages(REBINDING_TIMEOUT_MSG, componentShortString);
                     } else {
-                        Slog.w(TAG, "Bound to transport " + component.flattenToShortString() +
+                        Slog.w(TAG, "Bound to transport " + componentShortString +
                                 " but it is invalid");
                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
-                                component.flattenToShortString(), 0);
+                                componentShortString, 0);
                         mContext.unbindService(this);
                         mValidTransports.remove(component);
                         mBinder = null;
@@ -364,9 +378,27 @@
                 mBinder = null;
                 mBoundTransports.remove(mTransportName);
             }
-            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
-                    component.flattenToShortString(), 0);
-            Slog.w(TAG, "Disconnected from transport " + component.flattenToShortString());
+            String componentShortString = component.flattenToShortString();
+            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, componentShortString, 0);
+            Slog.w(TAG, "Disconnected from transport " + componentShortString);
+            scheduleRebindTimeout(component);
+        }
+
+        /**
+         * We'll attempt to explicitly rebind to a transport if it hasn't happened automatically
+         * for a few minutes after the binding went away.
+         */
+        private void scheduleRebindTimeout(ComponentName component) {
+            // we need to intern() the String of the component, so that we can use it with Handler's
+            // removeMessages(), which uses == operator to compare the tokens
+            final String componentShortString = component.flattenToShortString().intern();
+            final long rebindTimeout = getRebindTimeout();
+            mHandler.removeMessages(REBINDING_TIMEOUT_MSG, componentShortString);
+            Message msg = mHandler.obtainMessage(REBINDING_TIMEOUT_MSG);
+            msg.obj = componentShortString;
+            mHandler.sendMessageDelayed(msg, rebindTimeout);
+            Slog.d(TAG, "Scheduled explicit rebinding for " + componentShortString + " in "
+                    + rebindTimeout + "ms");
         }
 
         private IBackupTransport getBinder() {
@@ -403,6 +435,14 @@
                 }
             }
         }
+
+        private long getRebindTimeout() {
+            final boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+            return isDeviceProvisioned
+                    ? REBINDING_TIMEOUT_PROVISIONED_MS
+                    : REBINDING_TIMEOUT_UNPROVISIONED_MS;
+        }
     }
 
     interface TransportBoundListener {
@@ -410,6 +450,43 @@
         boolean onTransportBound(IBackupTransport binder);
     }
 
+    private class RebindOnTimeoutHandler extends Handler {
+
+        RebindOnTimeoutHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == REBINDING_TIMEOUT_MSG) {
+                String componentShortString = (String) msg.obj;
+                ComponentName transportComponent =
+                        ComponentName.unflattenFromString(componentShortString);
+                synchronized (mTransportLock) {
+                    if (mBoundTransports.containsValue(transportComponent)) {
+                        Slog.d(TAG, "Explicit rebinding timeout passed, but already bound to "
+                            + componentShortString + " so not attempting to rebind");
+                        return;
+                    }
+                    Slog.d(TAG, "Explicit rebinding timeout passed, attempting rebinding to: "
+                            + componentShortString);
+                    // unbind the existing (broken) connection
+                    TransportConnection conn = mValidTransports.get(transportComponent);
+                    if (conn != null) {
+                        mContext.unbindService(conn);
+                        Slog.d(TAG, "Unbinding the existing (broken) connection to transport: "
+                                + componentShortString);
+                    }
+                }
+                // rebind to transport
+                tryBindTransport(transportComponent);
+            } else {
+                Slog.e(TAG, "Unknown message sent to RebindOnTimeoutHandler, msg.what: "
+                        + msg.what);
+            }
+        }
+    }
+
     private static void log_verbose(String message) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Slog.v(TAG, message);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 3e2dae5..26b15d8 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -2865,8 +2865,9 @@
             if (arg != null) {
                 try {
                     addPowerSaveTempWhitelistAppChecked(arg, duration, shell.userId, "shell");
-                } catch (RemoteException re) {
-                    pw.println("Failed: " + re);
+                } catch (Exception e) {
+                    pw.println("Failed: " + e);
+                    return -1;
                 }
             } else {
                 dumpTempWhitelistSchedule(pw, false);
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 14a9a31..19bedfb 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -32,6 +32,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.IGraphicsStats;
 import android.view.IGraphicsStatsCallback;
@@ -167,7 +168,10 @@
         long callingIdentity = Binder.clearCallingIdentity();
         try {
             mAppOps.checkPackage(uid, packageName);
-            PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
+            PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(
+                    packageName,
+                    0,
+                    UserHandle.getUserId(uid));
             synchronized (mLock) {
                 pfd = requestBufferForProcessLocked(token, uid, pid, packageName, info.versionCode);
             }
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/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 46c9f25..78c0fe6 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -667,7 +667,7 @@
     @Override
     public boolean setActiveScorer(String packageName) {
         // Only the system can set the active scorer
-        if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
+        if (!isCallerSystemProcess(getCallingUid()) && !callerCanRequestScores()) {
             throw new SecurityException(
                     "Caller is neither the system process nor a score requester.");
         }
@@ -736,7 +736,7 @@
     @Override
     public List<NetworkScorerAppData> getAllValidScorers() {
         // Only the system can access this data.
-        if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
+        if (!isCallerSystemProcess(getCallingUid()) && !callerCanRequestScores()) {
             throw new SecurityException(
                     "Caller is neither the system process nor a score requester.");
         }
@@ -747,7 +747,7 @@
     @Override
     public void disableScoring() {
         // Only the active scorer or the system should be allowed to disable scoring.
-        if (!isCallerActiveScorer(getCallingUid()) || !callerCanRequestScores()) {
+        if (!isCallerActiveScorer(getCallingUid()) && !callerCanRequestScores()) {
             throw new SecurityException(
                     "Caller is neither the active scorer nor the scorer manager.");
         }
diff --git a/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java b/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java
new file mode 100644
index 0000000..6fd0256
--- /dev/null
+++ b/services/core/java/com/android/server/PreloadsFileCacheExpirationJobService.java
@@ -0,0 +1,85 @@
+/*
+ * 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.server;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import com.android.internal.R;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link JobService} that marks
+ * {@link Environment#getDataPreloadsFileCacheDirectory() preloaded file cache} as expired after a
+ * pre-configured timeout.
+ */
+public class PreloadsFileCacheExpirationJobService extends JobService {
+    private static final boolean DEBUG = false; // Do not submit with true
+    private static final String TAG = "PreloadsFileCacheExpirationJobService";
+
+    // TODO move all JOB_IDs into a single class to avoid collisions
+    private static final int JOB_ID = 100500;
+
+    private static final String PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED
+            = "persist.sys.preloads.file_cache_expired";
+
+    public static void schedule(Context context) {
+        int keepPreloadsMinDays = Resources.getSystem().getInteger(
+                R.integer.config_keepPreloadsMinDays); // Default is 1 week
+        long keepPreloadsMinTimeoutMs = DEBUG ? TimeUnit.MINUTES.toMillis(2)
+                : TimeUnit.DAYS.toMillis(keepPreloadsMinDays);
+        long keepPreloadsMaxTimeoutMs = DEBUG ? TimeUnit.MINUTES.toMillis(3)
+                : TimeUnit.DAYS.toMillis(keepPreloadsMinDays + 1);
+
+        if (DEBUG) {
+            StringBuilder sb = new StringBuilder("Scheduling expiration job to run in ");
+            TimeUtils.formatDuration(keepPreloadsMinTimeoutMs, sb);
+            Slog.i(TAG, sb.toString());
+        }
+        JobInfo expirationJob = new JobInfo.Builder(JOB_ID,
+                new ComponentName(context, PreloadsFileCacheExpirationJobService.class))
+                .setPersisted(true)
+                .setMinimumLatency(keepPreloadsMinTimeoutMs)
+                .setOverrideDeadline(keepPreloadsMaxTimeoutMs)
+                .build();
+
+        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        jobScheduler.schedule(expirationJob);
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        SystemProperties.set(PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED, "1");
+        Slog.i(TAG, "Set " + PERSIST_SYS_PRELOADS_FILE_CACHE_EXPIRED + "=1");
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index be021ea..ce4ca02 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -71,7 +71,6 @@
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
-        "media.codec",     // system/bin/mediacodec
         "media.extractor", // system/bin/mediaextractor
         "com.android.bluetooth",  // Bluetooth service
     };
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index f954f75..490e63d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -119,6 +119,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -210,10 +211,11 @@
         /** protected by the {@link #cacheLock} */
         private final TokenCache accountTokenCaches = new TokenCache();
 
-        /** protected by the {@link #cacheLock} */
-        // TODO use callback to set up the map.
-        private final Map<String, LinkedHashSet<String>> mApplicationAccountRequestMappings =
-                new HashMap<>();
+        /** protected by the {@link #mReceiversForType}
+         *  type -> (packageName -> number of active receivers)
+         *  type == null is used to get notifications about all account types
+         */
+        private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>();
 
         /**
          * protected by the {@link #cacheLock}
@@ -512,7 +514,7 @@
 
     @Override
     public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
-        if (account == null) throw new IllegalArgumentException("account is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
         int callingUid = Binder.getCallingUid();
         int userId = UserHandle.getUserId(callingUid);
         UserAccounts accounts = getUserAccounts(userId);
@@ -541,23 +543,23 @@
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
-
     }
 
     @Override
-    public int getAccountVisibility(Account a, String packageName) {
-        if (a == null) throw new IllegalArgumentException("account is null");
+    public int getAccountVisibility(Account account, String packageName) {
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
         int callingUid = Binder.getCallingUid();
-        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
+        if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
             && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot get secrets for accounts of type: %s",
                     callingUid,
-                    a.type);
+                    account.type);
             throw new SecurityException(msg);
         }
-        return resolveAccountVisibility(a, packageName,
-                getUserAccounts(UserHandle.getUserId(callingUid)));
+        return resolveAccountVisibility(account, packageName, accounts);
     }
 
     /**
@@ -573,7 +575,8 @@
     private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
         final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         try {
-            Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
+            Integer visibility =
+                accounts.accountsDb.findAccountVisibility(account, packageName);
             return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
@@ -592,6 +595,7 @@
      */
     private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
             UserAccounts accounts) {
+
         Preconditions.checkNotNull(packageName, "packageName cannot be null");
 
         int uid = -1;
@@ -693,19 +697,21 @@
     }
 
     @Override
-    public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
-        if (a == null) throw new IllegalArgumentException("account is null");
+    public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
         int callingUid = Binder.getCallingUid();
-        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
+        if (!isAccountManagedByCaller(account.type, callingUid, accounts.userId)
             && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot get secrets for accounts of type: %s",
                     callingUid,
-                    a.type);
+                    account.type);
             throw new SecurityException(msg);
         }
-        return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
-                getUserAccounts(UserHandle.getUserId(callingUid)));
+        return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
+                accounts);
     }
 
     /**
@@ -722,16 +728,18 @@
     private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
             boolean notify, UserAccounts accounts) {
         synchronized (accounts.cacheLock) {
-            LinkedHashSet<String> interestedPackages;
+            Map<String, Integer> packagesToVisibility;
             if (notify) {
                 if (isSpecialPackageKey(packageName)) {
-                    interestedPackages = getRequestingPackageNames(account.type, accounts);
+                    packagesToVisibility =
+                        getRequestingPackages(account, accounts);
                 } else {
                     if (!packageExistsForUser(packageName, accounts.userId)) {
                         return false; // package is not installed.
                     }
-                    interestedPackages = new LinkedHashSet<>();
-                    interestedPackages.add(packageName);
+                    packagesToVisibility = new HashMap<>();
+                    packagesToVisibility.put(packageName,
+                        resolveAccountVisibility(account, packageName, accounts));
                 }
             } else {
                 // Notifications will not be send.
@@ -740,19 +748,13 @@
                     // package is not installed and not meta value.
                     return false;
                 }
-                interestedPackages = new LinkedHashSet<>();
+                packagesToVisibility = new HashMap<>();
             }
-            Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
 
             final long accountId = accounts.accountsDb.findDeAccountId(account);
             if (accountId < 0) {
                 return false;
             }
-            int index = 0;
-            for (String interestedPackage : interestedPackages) {
-                interestedPackagesVisibility[index++] =
-                        resolveAccountVisibility(account, interestedPackage, accounts);
-            }
 
             final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
             try {
@@ -764,45 +766,113 @@
                 StrictMode.setThreadPolicy(oldPolicy);
             }
 
-            index = 0;
-            for (String interestedPackage : interestedPackages) {
-                int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
-                if (visibility != interestedPackagesVisibility[index++]) {
-                        sendNotification(interestedPackage, account, accounts.userId);
-                }
-            }
             if (notify) {
+                for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
+                    if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                        notifyPackage(packageToVisibility.getKey(), accounts);
+                    }
+                }
                 sendAccountsChangedBroadcast(accounts.userId);
             }
             return true;
         }
     }
 
-    /**
-     * Sends a direct intent to a package, notifying it of a visible account change.
-     *
-     * @param packageName to send Account to
-     * @param account to send to package
-     * @param userId User
-     */
-    private void sendNotification(String packageName, Account account, int userId) {
-        // TODO send notification so apps subscribed in runtime.
+    @Override
+    public void registerAccountListener(String[] accountTypes, String opPackageName) {
+        int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
+        registerAccountListener(accountTypes, opPackageName,
+            getUserAccounts(UserHandle.getUserId(callingUid)));
     }
 
-    private void sendNotification(Account account, UserAccounts accounts) {
-        LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
-                accounts);
-        for (String packageName : interestedPackages) {
-            int visibility = resolveAccountVisibility(account, packageName, accounts);
-            if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
-                sendNotification(packageName, account, accounts.userId);
+    private void registerAccountListener(String[] accountTypes, String opPackageName,
+            UserAccounts accounts) {
+        synchronized (accounts.mReceiversForType) {
+            if (accountTypes == null) {
+                // null for any type
+                accountTypes = new String[] {null};
+            }
+            for (String type : accountTypes) {
+                Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
+                if (receivers == null) {
+                    receivers = new HashMap<>();
+                    accounts.mReceiversForType.put(type, receivers);
+                }
+                Integer cnt = receivers.get(opPackageName);
+                receivers.put(opPackageName, cnt != null ? cnt + 1 : 1);
             }
         }
     }
 
-    LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
-        // TODO return packages registered to get notifications.
-        return new LinkedHashSet<String>();
+    @Override
+    public void unregisterAccountListener(String[] accountTypes, String opPackageName) {
+        int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
+        synchronized (accounts.mReceiversForType) {
+            if (accountTypes == null) {
+                // null for any type
+                accountTypes = new String[] {null};
+            }
+            for (String type : accountTypes) {
+                Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
+                if (receivers == null || receivers.get(opPackageName) == null) {
+                    throw new IllegalArgumentException("attempt to unregister wrong receiver");
+                }
+                Integer cnt = receivers.get(opPackageName);
+                if (cnt == 1) {
+                    receivers.remove(opPackageName);
+                } else {
+                    receivers.put(opPackageName, cnt - 1);
+                }
+            }
+        }
+    }
+
+    // Send notification to all packages which can potentially see the account
+    private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
+        Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
+        // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
+        // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
+        for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
+            if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                notifyPackage(packageToVisibility.getKey(), accounts);
+            }
+        }
+    }
+
+    /**
+     * Sends a direct intent to a package, notifying it of account visibility change.
+     *
+     * @param packageName to send Account to
+     * @param accounts UserAccount that currently hosts the account
+     */
+    private void notifyPackage(String packageName, UserAccounts accounts) {
+        Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
+        intent.setPackage(packageName);
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId));
+    }
+
+    // Returns a map from package name to visibility, for packages subscribed
+    // to notifications about any account type, or type of provided account
+    // account type or all types.
+    private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) {
+        Set<String> packages = new HashSet<>();
+        synchronized (accounts.mReceiversForType) {
+            for (String type : new String[] {account.type, null}) {
+                Map<String, Integer> receivers = accounts.mReceiversForType.get(type);
+                if (receivers != null) {
+                    packages.addAll(receivers.keySet());
+                }
+            }
+        }
+        Map<String, Integer> result = new HashMap<>();
+        for (String packageName : packages) {
+            result.put(packageName, resolveAccountVisibility(account, packageName, accounts));
+        }
+        return result;
     }
 
     private boolean packageExistsForUser(String packageName, int userId) {
@@ -950,6 +1020,8 @@
                     if (obsoleteAuthType.contains(account.type)) {
                         Slog.w(TAG, "deleting account " + account.name + " because type "
                                 + account.type + "'s registered authenticator no longer exist.");
+                        Map<String, Integer> packagesToVisibility =
+                            getRequestingPackages(account, accounts);
                         accountsDb.beginTransaction();
                         try {
                             accountsDb.deleteDeAccount(accountId);
@@ -970,12 +1042,12 @@
                         accounts.userDataCache.remove(account);
                         accounts.authTokenCache.remove(account);
                         accounts.accountTokenCaches.remove(account);
-                        LinkedHashSet<String> interestedPackages =
-                                getRequestingPackageNames(account.type, accounts);
-                        for (String packageName : interestedPackages) {
-                            sendNotification(packageName, null, accounts.userId);
-                        }
 
+                        for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
+                            if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                                notifyPackage(packageToVisibility.getKey(), accounts);
+                            }
+                        }
                     } else {
                         ArrayList<String> accountNames = accountNamesByType.get(account.type);
                         if (accountNames == null) {
@@ -1224,7 +1296,7 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
@@ -1260,8 +1332,8 @@
                     account, key, callingUid, Binder.getCallingPid());
             Log.v(TAG, msg);
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (key == null) throw new IllegalArgumentException("key is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(key, "key cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -1414,9 +1486,7 @@
                     callingUid);
             Log.v(TAG, msg);
         }
-        if (account == null) {
-            throw new IllegalArgumentException("account is null");
-        }
+        Preconditions.checkNotNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -1564,7 +1634,7 @@
             addAccountToLinkedRestrictedUsers(account, accounts.userId);
         }
 
-        sendNotification(account, accounts);
+        sendNotificationAccountUpdated(account, accounts);
         // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
         sendAccountsChangedBroadcast(accounts.userId);
 
@@ -1608,9 +1678,9 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (response == null) throw new IllegalArgumentException("response is null");
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (features == null) throw new IllegalArgumentException("features is null");
+        Preconditions.checkArgument(account != null, "account cannot be null");
+        Preconditions.checkArgument(response != null, "response cannot be null");
+        Preconditions.checkArgument(features != null, "features cannot be null");
         int userId = UserHandle.getCallingUserId();
         checkReadAccountsPermitted(callingUid, account.type, userId,
                 opPackageName);
@@ -1806,8 +1876,7 @@
                 }
             }
 
-            // Notify authenticator.
-            sendNotification(resultAccount, accounts);
+            sendNotificationAccountUpdated(resultAccount, accounts);
             sendAccountsChangedBroadcast(accounts.userId);
         }
         return resultAccount;
@@ -1839,8 +1908,9 @@
                     + ", pid " + Binder.getCallingPid()
                     + ", for user id " + userId);
         }
-        if (response == null) throw new IllegalArgumentException("response is null");
-        if (account == null) throw new IllegalArgumentException("account is null");
+        Preconditions.checkArgument(account != null, "account cannot be null");
+        Preconditions.checkArgument(response != null, "response cannot be null");
+
         // Only allow the system process to modify accounts of other users
         if (isCrossUser(callingUid, userId)) {
             throw new SecurityException(
@@ -2006,17 +2076,7 @@
                     + " is still locked. CE data will be removed later");
         }
         synchronized (accounts.cacheLock) {
-            LinkedHashSet<String> interestedPackages =
-                    accounts.mApplicationAccountRequestMappings.get(account.type);
-            if (interestedPackages == null) {
-                interestedPackages = new LinkedHashSet<>();
-            }
-            int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
-            int index = 0;
-            for (String packageName : interestedPackages) {
-                int visibility = resolveAccountVisibility(account, packageName, accounts);
-                visibilityForInterestedPackages[index++] = visibility;
-            }
+            Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
             accounts.accountsDb.beginTransaction();
             // Set to a dummy value, this will only be used if the database
             // transaction succeeds.
@@ -2040,18 +2100,13 @@
             }
             if (isChanged) {
                 removeAccountFromCacheLocked(accounts, account);
-                index = 0;
-                for (String packageName : interestedPackages) {
-                    if ((visibilityForInterestedPackages[index]
-                            != AccountManager.VISIBILITY_NOT_VISIBLE)
-                            && (visibilityForInterestedPackages[index]
-                                    != AccountManager.VISIBILITY_UNDEFINED)) {
-                        sendNotification(packageName, account, accounts.userId);
+                for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
+                    if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                        notifyPackage(packageToVisibility.getKey(), accounts);
                     }
-                    ++index;
                 }
 
-                // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
+                // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
                 sendAccountsChangedBroadcast(accounts.userId);
                 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
                         : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
@@ -2094,13 +2149,13 @@
     @Override
     public void invalidateAuthToken(String accountType, String authToken) {
         int callerUid = Binder.getCallingUid();
+        Preconditions.checkNotNull(accountType, "accountType cannot be null");
+        Preconditions.checkNotNull(authToken, "authToken cannot be null");
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
                     + ", caller's uid " + callerUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (accountType == null) throw new IllegalArgumentException("accountType is null");
-        if (authToken == null) throw new IllegalArgumentException("authToken is null");
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
@@ -2210,8 +2265,8 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2243,8 +2298,8 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2270,7 +2325,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2317,7 +2372,7 @@
                 accounts.accountsDb.endTransaction();
                 if (isChanged) {
                     // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
-                    sendNotification(account, accounts);
+                    sendNotificationAccountUpdated(account, accounts);
                     sendAccountsChangedBroadcast(accounts.userId);
                 }
             }
@@ -2332,7 +2387,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        if (account == null) throw new IllegalArgumentException("account is null");
+        Preconditions.checkNotNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2444,8 +2499,8 @@
     public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
                                   final String authTokenType)
             throws RemoteException {
-        if (accountType == null) throw new IllegalArgumentException("accountType is null");
-        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        Preconditions.checkArgument(accountType != null, "accountType cannot be null");
+        Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
 
         final int callingUid = getCallingUid();
         clearCallingIdentity();
@@ -2508,7 +2563,7 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        if (response == null) throw new IllegalArgumentException("response is null");
+        Preconditions.checkArgument(response != null, "response cannot be null");
         try {
             if (account == null) {
                 Slog.w(TAG, "getAuthToken called with null account");
@@ -2909,8 +2964,8 @@
                     + ", pid " + Binder.getCallingPid()
                     + ", for user id " + userId);
         }
-        if (response == null) throw new IllegalArgumentException("response is null");
-        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        Preconditions.checkArgument(response != null, "response cannot be null");
+        Preconditions.checkArgument(accountType != null, "accountType cannot be null");
         // Only allow the system process to add accounts of other users
         if (isCrossUser(callingUid, userId)) {
             throw new SecurityException(
@@ -2996,12 +3051,8 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        if (response == null) {
-            throw new IllegalArgumentException("response is null");
-        }
-        if (accountType == null) {
-            throw new IllegalArgumentException("accountType is null");
-        }
+        Preconditions.checkArgument(response != null, "response cannot be null");
+        Preconditions.checkArgument(accountType != null, "accountType cannot be null");
 
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(uid);
@@ -3190,10 +3241,7 @@
                             + ", pid " + Binder.getCallingPid()
                             + ", for user id " + userId);
         }
-        if (response == null) {
-            throw new IllegalArgumentException("response is null");
-        }
-
+        Preconditions.checkArgument(response != null, "response cannot be null");
         // Session bundle is the encrypted bundle of the original bundle created by authenticator.
         // Account type is added to it before encryption.
         if (sessionBundle == null || sessionBundle.size() == 0) {
@@ -3690,9 +3738,9 @@
         // the account to be accessed by apps for which user or authenticator granted visibility.
 
         int visibility = resolveAccountVisibility(account, packageName,
-                getUserAccounts(UserHandle.getUserId(uid)));
+            getUserAccounts(UserHandle.getUserId(uid)));
         return (visibility == AccountManager.VISIBILITY_VISIBLE
-                || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+            || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
     }
 
     @Override
@@ -4843,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();
@@ -5630,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 5956923..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;
@@ -298,6 +295,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionSession;
+import android.service.vr.IPersistentVrStateCallbacks;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -370,7 +368,6 @@
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.PersistentVrStateListener;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.WindowManagerService;
 
@@ -627,8 +624,8 @@
     private int mVrState = NON_VR_MODE;
     private int mTopAppVrThreadTid = 0;
     private int mPersistentVrThreadTid = 0;
-    final PersistentVrStateListener mPersistentVrModeListener =
-            new PersistentVrStateListener() {
+    final IPersistentVrStateCallbacks mPersistentVrModeListener =
+            new IPersistentVrStateCallbacks.Stub() {
         @Override
         public void onPersistentVrStateChanged(boolean enabled) {
             synchronized(ActivityManagerService.this) {
@@ -1185,13 +1182,13 @@
 
         @Override
         public String toString() {
-            String result = Integer.toString(sourceUserId) + " @ " + uri.toString();
+            String result = uri.toString() + " [user " + sourceUserId + "]";
             if (prefix) result += " [prefix]";
             return result;
         }
 
         public String toSafeString() {
-            String result = Integer.toString(sourceUserId) + " @ " + uri.toSafeString();
+            String result = uri.toSafeString() + " [user " + sourceUserId + "]";
             if (prefix) result += " [prefix]";
             return result;
         }
@@ -8671,8 +8668,15 @@
         if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
             // Require they hold a strong enough Uri permission
             if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
-                throw new SecurityException("Uid " + callingUid
-                        + " does not have permission to uri " + grantUri);
+                if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
+                    throw new SecurityException(
+                            "UID " + callingUid + " does not have permission to " + grantUri
+                                    + "; you could obtain access using ACTION_OPEN_DOCUMENT "
+                                    + "or related APIs");
+                } else {
+                    throw new SecurityException(
+                            "UID " + callingUid + " does not have permission to " + grantUri);
+                }
             }
         }
         return targetUid;
@@ -10844,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
     // =========================================================
@@ -10927,7 +10950,8 @@
         } catch (RemoteException ignored) {
         }
         if (cpi == null) {
-            return "Failed to find provider " + authority + " for user " + userId;
+            return "Failed to find provider " + authority + " for user " + userId
+                    + "; expected to find a valid ContentProvider for this authority";
         }
 
         ProcessRecord r = null;
@@ -11007,18 +11031,17 @@
             return null;
         }
 
-        String msg;
+        final String suffix;
         if (!cpi.exported) {
-            msg = "Permission Denial: opening provider " + cpi.name
-                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ") that is not exported from uid "
-                    + cpi.applicationInfo.uid;
+            suffix = " that is not exported from UID " + cpi.applicationInfo.uid;
+        } else if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(cpi.readPermission)) {
+            suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
         } else {
-            msg = "Permission Denial: opening provider " + cpi.name
-                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ") requires "
-                    + cpi.readPermission + " or " + cpi.writePermission;
+            suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
         }
+        final String msg = "Permission Denial: opening provider " + cpi.name
+                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+                + ", uid=" + callingUid + ")" + suffix;
         Slog.w(TAG, msg);
         return msg;
     }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index dd8c05e..04a09fe 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -321,6 +321,7 @@
             if (info.launchedActivity.info.launchToken != null) {
                 builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN,
                         info.launchedActivity.info.launchToken);
+                info.launchedActivity.info.launchToken = null;
             }
             builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL,
                     info.launchedActivity.info.applicationInfo.isInstantApp() ? 1 : 0);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7868fdf..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.
@@ -2391,6 +2395,10 @@
         return (config.uiMode & Configuration.UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
     }
 
+    int getUid() {
+        return info.applicationInfo.uid;
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e64b4b3..9a4f804 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -741,8 +741,10 @@
     /** Checks if there are tasks with specific UID in the stack. */
     boolean isUidPresent(int uid) {
         for (TaskRecord task : mTaskHistory) {
-            if (task.effectiveUid == uid) {
-                return true;
+            for (ActivityRecord r : task.mActivities) {
+                if (r.getUid() == uid) {
+                    return true;
+                }
             }
         }
         return false;
@@ -751,7 +753,9 @@
     /** Get all UIDs that are present in the stack. */
     void getPresentUIDs(IntArray presentUIDs) {
         for (TaskRecord task : mTaskHistory) {
-            presentUIDs.add(task.effectiveUid);
+            for (ActivityRecord r : task.mActivities) {
+                presentUIDs.add(r.getUid());
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c1bff36..5c49dfd 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1227,6 +1227,10 @@
                     mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
                 }
             }
+            final String intentLaunchToken = intent.getLaunchToken();
+            if (aInfo.launchToken == null && intentLaunchToken != null) {
+                aInfo.launchToken = intentLaunchToken;
+            }
         }
         return aInfo;
     }
@@ -1632,7 +1636,11 @@
         mDisplayAccessUIDs.clear();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
-            mDisplayAccessUIDs.append(activityDisplay.mDisplayId, activityDisplay.getPresentUIDs());
+            // Only bother calculating the whitelist for private displays
+            if (activityDisplay.isPrivate()) {
+                mDisplayAccessUIDs.append(
+                        activityDisplay.mDisplayId, activityDisplay.getPresentUIDs());
+            }
         }
         // Store updated lists in DisplayManager. Callers from outside of AM should get them there.
         mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs);
@@ -2287,7 +2295,18 @@
         mResizingTasksDuringAnimation.clear();
     }
 
-    void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) {
+    private class MoveTaskToFullscreenArgs {
+        public int fromStackId;
+        public boolean onTop;
+    };
+    // Used only to closure over the arguments to moveTasksToFullscreenStack without
+    // allocation
+    private MoveTaskToFullscreenArgs mMoveToFullscreenArgs = new MoveTaskToFullscreenArgs();
+
+    private void moveTasksToFullscreenStackInnerLocked() {
+        int fromStackId = mMoveToFullscreenArgs.fromStackId;
+        boolean onTop = mMoveToFullscreenArgs.onTop;
+
         final ActivityStack stack = getStack(fromStackId);
         if (stack == null) {
             return;
@@ -2359,6 +2378,13 @@
         }
     }
 
+    void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) {
+        mMoveToFullscreenArgs.fromStackId = fromStackId;
+        mMoveToFullscreenArgs.onTop = onTop;
+
+        mWindowManager.inSurfaceTransaction(this::moveTasksToFullscreenStackInnerLocked);
+    }
+
     void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
             boolean preserveWindows) {
@@ -2471,12 +2497,12 @@
         return activityContainer.mStack;
     }
 
-    /**
-     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
-     * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
-     * instead moved back onto the fullscreen stack.
-     */
-    void removeStackLocked(int stackId) {
+
+    // Used only to closure over the argument to removeStack without allocation.
+    private int mRemoveStackStackId;
+    void removeStackInnerLocked() {
+        int stackId = mRemoveStackStackId;
+
         final ActivityStack stack = getStack(stackId);
         if (stack == null) {
             return;
@@ -2515,6 +2541,16 @@
     }
 
     /**
+     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
+     * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
+     * instead moved back onto the fullscreen stack.
+     */
+    void removeStackLocked(int stackId) {
+        mRemoveStackStackId = stackId;
+        mWindowManager.inSurfaceTransaction(this::removeStackInnerLocked);
+    }
+
+    /**
      * Removes the task with the specified task id.
      *
      * @param taskId Identifier of the task to be removed.
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 13c8865..a668fea 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1236,6 +1236,10 @@
             mWindowContainerController.positionChildAt(appController, index);
         }
         r.onOverrideConfigurationSent();
+
+        // Make sure the list of display UID whitelists is updated
+        // now that this record is in a new task.
+        mService.mStackSupervisor.updateUIDsPresentOnDisplay();
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 34826b6..d56fb1a 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.connectivity;
 
+import android.annotation.WorkerThread;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -74,7 +75,7 @@
     public static final String KEY_PROXY = "keyProxy";
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
-    private Uri mPacUrl = Uri.EMPTY;
+    private volatile Uri mPacUrl = Uri.EMPTY;
 
     private AlarmManager mAlarmManager;
     @GuardedBy("mProxyLock")
@@ -87,33 +88,37 @@
     private int mCurrentDelay;
     private int mLastPort;
 
-    private boolean mHasSentBroadcast;
-    private boolean mHasDownloaded;
+    private volatile boolean mHasSentBroadcast;
+    private volatile boolean mHasDownloaded;
 
     private Handler mConnectivityHandler;
     private int mProxyMessage;
 
     /**
-     * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
+     * Used for locking when setting mProxyService and all references to mCurrentPac.
      */
     private final Object mProxyLock = new Object();
 
+    /**
+     * Runnable to download PAC script.
+     * The behavior relies on the assamption it always run on mNetThread to guarantee that the
+     * latest data fetched from mPacUrl is stored in mProxyService.
+     */
     private Runnable mPacDownloader = new Runnable() {
         @Override
+        @WorkerThread
         public void run() {
             String file;
-            synchronized (mProxyLock) {
-                if (Uri.EMPTY.equals(mPacUrl)) return;
-                final int oldTag = TrafficStats
-                        .getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC);
-                try {
-                    file = get(mPacUrl);
-                } catch (IOException ioe) {
-                    file = null;
-                    Log.w(TAG, "Failed to load PAC file: " + ioe);
-                } finally {
-                    TrafficStats.setThreadStatsTag(oldTag);
-                }
+            final Uri pacUrl = mPacUrl;
+            if (Uri.EMPTY.equals(pacUrl)) return;
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC);
+            try {
+                file = get(pacUrl);
+            } catch (IOException ioe) {
+                file = null;
+                Log.w(TAG, "Failed to load PAC file: " + ioe);
+            } finally {
+                TrafficStats.setThreadStatsTag(oldTag);
             }
             if (file != null) {
                 synchronized (mProxyLock) {
@@ -176,9 +181,7 @@
                 // Allow to send broadcast, nothing to do.
                 return false;
             }
-            synchronized (mProxyLock) {
-                mPacUrl = proxy.getPacFileUrl();
-            }
+            mPacUrl = proxy.getPacFileUrl();
             mCurrentDelay = DELAY_1;
             mHasSentBroadcast = false;
             mHasDownloaded = false;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index a947b41..f9bc12b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -62,7 +62,18 @@
 
     private final int mDisplayId;
     private final int mLayerStack;
-    private DisplayInfo mOverrideDisplayInfo; // set by the window manager
+    /**
+     * Override information set by the window manager. Will be reported instead of {@link #mInfo}
+     * if not null.
+     * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo)
+     * @see #getDisplayInfoLocked()
+     */
+    private DisplayInfo mOverrideDisplayInfo;
+    /**
+     * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if
+     * needs to be updated.
+     * @see #getDisplayInfoLocked()
+     */
     private DisplayInfo mInfo;
 
     // The display device that this logical display is based on and which
@@ -261,6 +272,9 @@
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo = null;
+            // Make sure that WM will be notified of new changes. It will then decide whether to
+            // apply them or not and will set the value again.
+            mOverrideDisplayInfo = null;
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 06f0144..7e10a09 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1306,14 +1306,16 @@
             mRankingHelper.updateNotificationChannel(pkg, uid, channel);
         }
 
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             final int N = mNotificationList.size();
             for (int i = N - 1; i >= 0; --i) {
                 NotificationRecord r = mNotificationList.get(i);
-                if (channel.getId() != null && channel.getId().equals(r.getChannel().getId())) {
+                if (r.sbn.getPackageName().equals(pkg)
+                        && r.sbn.getUid() == uid
+                        && channel.getId() != null
+                        && channel.getId().equals(r.getChannel().getId())) {
                     r.updateNotificationChannel(mRankingHelper.getNotificationChannel(
-                            r.sbn.getPackageName(), r.getUser().getIdentifier(),
-                            channel.getId(), false));
+                            pkg, uid, channel.getId(), false));
                 }
             }
         }
@@ -3107,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/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d751a22..b043230 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -294,8 +294,9 @@
         stats.isNoisy = mSound != null || mVibration != null;
 
         if (mPreChannelsNotification
-                && (getChannel().getUserLockedFields()
-                & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) {
+                && (importance == IMPORTANCE_UNSPECIFIED
+                || (getChannel().getUserLockedFields()
+                & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
             if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
                 requestedImportance = IMPORTANCE_LOW;
             }
@@ -358,6 +359,7 @@
     }
 
     void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
+        prefix = prefix + "  ";
         final Notification notification = sbn.getNotification();
         final Icon icon = notification.getSmallIcon();
         String iconStr = String.valueOf(icon);
@@ -365,21 +367,21 @@
             iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
         }
         pw.println(prefix + this);
-        pw.println(prefix + "  uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
-        pw.println(prefix + "  icon=" + iconStr);
-        pw.println(prefix + "  pri=" + notification.priority);
-        pw.println(prefix + "  key=" + sbn.getKey());
-        pw.println(prefix + "  seen=" + mIsSeen);
-        pw.println(prefix + "  groupKey=" + getGroupKey());
-        pw.println(prefix + "  fullscreenIntent=" + notification.fullScreenIntent);
-        pw.println(prefix + "  contentIntent=" + notification.contentIntent);
-        pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
-        pw.println(prefix + "  tickerText=" + notification.tickerText);
-        pw.println(prefix + "  contentView=" + notification.contentView);
-        pw.println(prefix + String.format("  color=0x%08x", notification.color));
-        pw.println(prefix + "  timeout=" + TimeUtils.formatForLogging(notification.getTimeout()));
+        pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
+        pw.println(prefix + "icon=" + iconStr);
+        pw.println(prefix + "pri=" + notification.priority);
+        pw.println(prefix + "key=" + sbn.getKey());
+        pw.println(prefix + "seen=" + mIsSeen);
+        pw.println(prefix + "groupKey=" + getGroupKey());
+        pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
+        pw.println(prefix + "contentIntent=" + notification.contentIntent);
+        pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
+        pw.println(prefix + "tickerText=" + notification.tickerText);
+        pw.println(prefix + "contentView=" + notification.contentView);
+        pw.println(prefix + String.format("color=0x%08x", notification.color));
+        pw.println(prefix + "timeout=" + TimeUtils.formatForLogging(notification.getTimeout()));
         if (notification.actions != null && notification.actions.length > 0) {
-            pw.println(prefix + "  actions={");
+            pw.println(prefix + "actions={");
             final int N = notification.actions.length;
             for (int i = 0; i < N; i++) {
                 final Notification.Action action = notification.actions[i];
@@ -395,7 +397,7 @@
             pw.println(prefix + "  }");
         }
         if (notification.extras != null && notification.extras.size() > 0) {
-            pw.println(prefix + "  extras={");
+            pw.println(prefix + "extras={");
             for (String key : notification.extras.keySet()) {
                 pw.print(prefix + "    " + key + "=");
                 Object val = notification.extras.get(key);
@@ -425,46 +427,46 @@
                     pw.println();
                 }
             }
-            pw.println(prefix + "  }");
+            pw.println(prefix + "}");
         }
-        pw.println(prefix + "  stats=" + stats.toString());
-        pw.println(prefix + "  mContactAffinity=" + mContactAffinity);
-        pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
-        pw.println(prefix + "  mPackagePriority=" + mPackagePriority);
-        pw.println(prefix + "  mPackageVisibility=" + mPackageVisibility);
-        pw.println(prefix + "  mUserImportance="
+        pw.println(prefix + "stats=" + stats.toString());
+        pw.println(prefix + "mContactAffinity=" + mContactAffinity);
+        pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
+        pw.println(prefix + "mPackagePriority=" + mPackagePriority);
+        pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
+        pw.println(prefix + "mUserImportance="
                 + NotificationListenerService.Ranking.importanceToString(mUserImportance));
-        pw.println(prefix + "  mImportance="
+        pw.println(prefix + "mImportance="
                 + NotificationListenerService.Ranking.importanceToString(mImportance));
-        pw.println(prefix + "  mImportanceExplanation=" + mImportanceExplanation);
-        pw.println(prefix + "  mIntercept=" + mIntercept);
-        pw.println(prefix + "  mGlobalSortKey=" + mGlobalSortKey);
-        pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
-        pw.println(prefix + "  mCreationTimeMs=" + mCreationTimeMs);
-        pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
-        pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
-        pw.println(prefix + "  mSuppressedVisualEffects= " + mSuppressedVisualEffects);
+        pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
+        pw.println(prefix + "mIntercept=" + mIntercept);
+        pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
+        pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
+        pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
+        pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
+        pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
+        pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
         if (mPreChannelsNotification) {
-            pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
+            pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
-            pw.println(prefix + "  n.sound=" + notification.sound);
-            pw.println(prefix + "  n.audioStreamType=" + notification.audioStreamType);
-            pw.println(prefix + "  n.audioAttributes=" + notification.audioAttributes);
+            pw.println(prefix + "n.sound=" + notification.sound);
+            pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
+            pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
             pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
                     notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
-            pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
+            pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
         }
-        pw.println(prefix + "  mSound= " + mSound);
-        pw.println(prefix + "  mVibration= " + mVibration);
-        pw.println(prefix + "  mAttributes= " + mAttributes);
-        pw.println(prefix + "  mLight= " + mLight);
-        pw.println(prefix + "  mShowBadge=" + mShowBadge);
-        pw.println(prefix + "  effectiveNotificationChannel=" + getChannel());
+        pw.println(prefix + "mSound= " + mSound);
+        pw.println(prefix + "mVibration= " + mVibration);
+        pw.println(prefix + "mAttributes= " + mAttributes);
+        pw.println(prefix + "mLight= " + mLight);
+        pw.println(prefix + "mShowBadge=" + mShowBadge);
+        pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
         if (getPeopleOverride() != null) {
-            pw.println(prefix + "  overridePeople= " + TextUtils.join(",", getPeopleOverride()));
+            pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
         }
         if (getSnoozeCriteria() != null) {
-            pw.println(prefix + "  snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
+            pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index ce79465..73afaa0 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -201,7 +201,7 @@
                             // Channels
                             if (TAG_CHANNEL.equals(tagName)) {
                                 String id = parser.getAttributeValue(null, ATT_ID);
-                                CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
+                                String channelName = parser.getAttributeValue(null, ATT_NAME);
                                 int channelImportance =
                                         safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                                 if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
@@ -546,7 +546,8 @@
                 existing.setDeleted(false);
             }
 
-            existing.setName(channel.getName());
+            existing.setName(channel.getName().toString());
+            existing.setDescription(channel.getDescription());
 
             MetricsLogger.action(getChannelLog(channel, pkg));
             updateConfig();
@@ -683,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/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 86124a8..59f8a2d 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -200,6 +200,7 @@
             // Intent that is launched if the package couldn't be installed for any reason.
             final Intent failureIntent = new Intent(origIntent);
             failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+            failureIntent.setLaunchToken(token);
             try {
                 final IIntentSender failureIntentTarget = ActivityManager.getService()
                         .getIntentSender(
@@ -216,6 +217,7 @@
 
             // Intent that is launched if the package was installed successfully.
             final Intent successIntent = new Intent(origIntent);
+            successIntent.setLaunchToken(token);
             try {
                 final IIntentSender successIntentTarget = ActivityManager.getService()
                         .getIntentSender(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 837aa32..96e2626 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2879,24 +2879,17 @@
             }
 
             mInstallerService = new PackageInstallerService(context, this);
-
             final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
             if (ephemeralResolverComponent != null) {
                 if (DEBUG_EPHEMERAL) {
-                    Slog.i(TAG, "Ephemeral resolver: " + ephemeralResolverComponent);
+                    Slog.d(TAG, "Set ephemeral resolver: " + ephemeralResolverComponent);
                 }
                 mInstantAppResolverConnection =
                         new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
             } else {
                 mInstantAppResolverConnection = null;
             }
-            mInstantAppInstallerComponent = getEphemeralInstallerLPr();
-            if (mInstantAppInstallerComponent != null) {
-                if (DEBUG_EPHEMERAL) {
-                    Slog.i(TAG, "Ephemeral installer: " + mInstantAppInstallerComponent);
-                }
-                setUpInstantAppInstallerActivityLP(mInstantAppInstallerComponent);
-            }
+            updateInstantAppInstallerLocked();
 
             // Read and update the usage of dex files.
             // Do this at the end of PM init so that all the packages have their
@@ -2936,6 +2929,21 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
+    private void updateInstantAppInstallerLocked() {
+        final ComponentName oldInstantAppInstallerComponent = mInstantAppInstallerComponent;
+        final ComponentName newInstantAppInstallerComponent = getEphemeralInstallerLPr();
+        if (newInstantAppInstallerComponent != null
+                && !newInstantAppInstallerComponent.equals(oldInstantAppInstallerComponent)) {
+            if (DEBUG_EPHEMERAL) {
+                Slog.d(TAG, "Set ephemeral installer: " + newInstantAppInstallerComponent);
+            }
+            setUpInstantAppInstallerActivityLP(newInstantAppInstallerComponent);
+        } else if (DEBUG_EPHEMERAL && newInstantAppInstallerComponent == null) {
+            Slog.d(TAG, "Unset ephemeral installer; none available");
+        }
+        mInstantAppInstallerComponent = newInstantAppInstallerComponent;
+    }
+
     private static File preparePackageParserCache(boolean isUpgrade) {
         if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
             return null;
@@ -16918,6 +16926,7 @@
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 updateSequenceNumberLP(pkgName, res.newUsers);
+                updateInstantAppInstallerLocked();
             }
         }
     }
@@ -17493,6 +17502,7 @@
                         mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers);
                     }
                     updateSequenceNumberLP(packageName, info.removedUsers);
+                    updateInstantAppInstallerLocked();
                 }
             }
         }
@@ -18646,7 +18656,7 @@
     public void getPackageSizeInfo(final String packageName, int userHandle,
             final IPackageStatsObserver observer) {
         throw new UnsupportedOperationException(
-                "Shame on you for calling a hidden API. Shame!");
+                "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
     }
 
     private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
@@ -19838,6 +19848,7 @@
             }
             scheduleWritePackageRestrictionsLocked(userId);
             updateSequenceNumberLP(packageName, new int[] { userId });
+            updateInstantAppInstallerLocked();
             components = mPendingBroadcasts.get(userId, packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9ce7fef..31e22b9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -183,6 +183,7 @@
 import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.service.vr.IPersistentVrStateCallbacks;
 import android.speech.RecognizerIntent;
 import android.telecom.TelecomManager;
 import android.util.DisplayMetrics;
@@ -237,7 +238,6 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 import com.android.server.vr.VrManagerInternal;
-import com.android.server.vr.PersistentVrStateListener;
 
 import java.io.File;
 import java.io.FileReader;
@@ -1000,8 +1000,8 @@
     }
     MyOrientationListener mOrientationListener;
 
-    final PersistentVrStateListener mPersistentVrModeListener =
-            new PersistentVrStateListener() {
+    final IPersistentVrStateCallbacks mPersistentVrModeListener =
+            new IPersistentVrStateCallbacks.Stub() {
         @Override
         public void onPersistentVrStateChanged(boolean enabled) {
             mPersistentVrModeEnabled = enabled;
@@ -2402,7 +2402,9 @@
 
         ApplicationInfo appInfo;
         try {
-            appInfo = mContext.getPackageManager().getApplicationInfo(attrs.packageName,
+            appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
+                            attrs.packageName,
+                            0 /* flags */,
                             UserHandle.getUserId(callingUid));
         } catch (PackageManager.NameNotFoundException e) {
             appInfo = null;
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/vr/PersistentVrStateListener.java b/services/core/java/com/android/server/vr/PersistentVrStateListener.java
deleted file mode 100644
index bccd5f1..0000000
--- a/services/core/java/com/android/server/vr/PersistentVrStateListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * 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.server.vr;
-
-/**
- * Listener for state changes to persistent VR mode.
- *
- * @hide Only for use within system server.
- */
-public abstract class PersistentVrStateListener {
-
-  /**
-   * Called when the Persistent VR mode state changes.
-   *
-   * @param enabled {@code true} if persistent VR mode is enabled.
-   */
-    public abstract void onPersistentVrStateChanged(boolean enabled);
-}
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 210aa44..358861d 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
+import android.service.vr.IPersistentVrStateCallbacks;
 
 /**
  * Service for accessing the VR mode manager.
@@ -101,5 +102,5 @@
     /**
      * Adds listener that reports state changes to persistent VR mode.
      */
-    public abstract void addPersistentVrModeStateListener(PersistentVrStateListener listener);
+    public abstract void addPersistentVrModeStateListener(IPersistentVrStateCallbacks listener);
 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index a00115c..5bcdd4c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -40,6 +40,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
+import android.service.vr.IPersistentVrStateCallbacks;
 import android.service.vr.IVrListener;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -123,10 +124,10 @@
     private int mCurrentVrModeUser;
     private boolean mWasDefaultGranted;
     private boolean mGuard;
-    private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks =
+    private final RemoteCallbackList<IVrStateCallbacks> mVrStateRemoteCallbacks =
             new RemoteCallbackList<>();
-    private final ArrayList<PersistentVrStateListener> mPersistentVrStateListeners =
-            new ArrayList<>();
+    private final RemoteCallbackList<IPersistentVrStateCallbacks>
+            mPersistentVrStateRemoteCallbacks = new RemoteCallbackList<>();
     private int mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
     private int mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
     private VrState mPendingState;
@@ -202,16 +203,16 @@
             switch(msg.what) {
                 case MSG_VR_STATE_CHANGE : {
                     boolean state = (msg.arg1 == 1);
-                    int i = mRemoteCallbacks.beginBroadcast();
+                    int i = mVrStateRemoteCallbacks.beginBroadcast();
                     while (i > 0) {
                         i--;
                         try {
-                            mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state);
+                            mVrStateRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state);
                         } catch (RemoteException e) {
                             // Noop
                         }
                     }
-                    mRemoteCallbacks.finishBroadcast();
+                    mVrStateRemoteCallbacks.finishBroadcast();
                 } break;
                 case MSG_PENDING_VR_STATE_CHANGE : {
                     synchronized(mLock) {
@@ -222,10 +223,17 @@
                 } break;
                 case MSG_PERSISTENT_VR_MODE_STATE_CHANGE : {
                     boolean state = (msg.arg1 == 1);
-                    for (int i = 0; i < mPersistentVrStateListeners.size(); i++) {
-                        mPersistentVrStateListeners.get(i).onPersistentVrStateChanged(
-                                state);
+                    int i = mPersistentVrStateRemoteCallbacks.beginBroadcast();
+                    while (i > 0) {
+                        i--;
+                        try {
+                            mPersistentVrStateRemoteCallbacks.getBroadcastItem(i)
+                                    .onPersistentVrStateChanged(state);
+                        } catch (RemoteException e) {
+                            // Noop
+                        }
                     }
+                    mPersistentVrStateRemoteCallbacks.finishBroadcast();
                 } break;
                 default :
                     throw new IllegalStateException("Unknown message type: " + msg.what);
@@ -383,6 +391,26 @@
         }
 
         @Override
+        public void registerPersistentVrStateListener(IPersistentVrStateCallbacks cb) {
+            enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+            if (cb == null) {
+                throw new IllegalArgumentException("Callback binder object is null.");
+            }
+
+            VrManagerService.this.addPersistentStateCallback(cb);
+        }
+
+        @Override
+        public void unregisterPersistentVrStateListener(IPersistentVrStateCallbacks cb) {
+            enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+            if (cb == null) {
+                throw new IllegalArgumentException("Callback binder object is null.");
+            }
+
+            VrManagerService.this.removePersistentStateCallback(cb);
+        }
+
+        @Override
         public boolean getVrModeState() {
             return VrManagerService.this.getVrMode();
         }
@@ -414,13 +442,21 @@
             String tab = "  ";
             dumpStateTransitions(pw);
             pw.println("\n\nRemote Callbacks:");
-            int i=mRemoteCallbacks.beginBroadcast(); // create the broadcast item array
+            int i=mVrStateRemoteCallbacks.beginBroadcast(); // create the broadcast item array
             while(i-->0) {
                 pw.print(tab);
-                pw.print(mRemoteCallbacks.getBroadcastItem(i));
+                pw.print(mVrStateRemoteCallbacks.getBroadcastItem(i));
                 if (i>0) pw.println(",");
             }
-            mRemoteCallbacks.finishBroadcast();
+            mVrStateRemoteCallbacks.finishBroadcast();
+            pw.println("\n\nPersistent Vr State Remote Callbacks:");
+            i=mPersistentVrStateRemoteCallbacks.beginBroadcast();
+            while(i-->0) {
+                pw.print(tab);
+                pw.print(mPersistentVrStateRemoteCallbacks.getBroadcastItem(i));
+                if (i>0) pw.println(",");
+            }
+            mPersistentVrStateRemoteCallbacks.finishBroadcast();
             pw.println("\n");
             pw.println("Installed VrListenerService components:");
             int userId = mCurrentVrModeUser;
@@ -443,16 +479,6 @@
                     pw.println(n.flattenToString());
                 }
             }
-            pw.println("Attached persistent mode listeners:");
-            if (mPersistentVrStateListeners == null ||
-                    mPersistentVrStateListeners.size() == 0) {
-                pw.println("None");
-            } else {
-                for (PersistentVrStateListener l : mPersistentVrStateListeners) {
-                    pw.print(tab);
-                    pw.println("listener: " + l);
-                }
-            }
             pw.println("\n");
             pw.println("********* End of VrManagerService Dump *********");
         }
@@ -507,8 +533,8 @@
         }
 
         @Override
-        public void addPersistentVrModeStateListener(PersistentVrStateListener listener) {
-            VrManagerService.this.addPersistentVrModeStateListener(listener);
+        public void addPersistentVrModeStateListener(IPersistentVrStateCallbacks listener) {
+            VrManagerService.this.addPersistentStateCallback(listener);
         }
     }
 
@@ -1084,12 +1110,6 @@
                 (mPersistentVrModeEnabled) ? 1 : 0, 0));
     }
 
-    private void addPersistentVrModeStateListener(PersistentVrStateListener listener) {
-        synchronized (mLock) {
-            mPersistentVrStateListeners.add(listener);
-        }
-    }
-
     private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
         synchronized (mLock) {
             return mComponentObserver.isValid(targetPackageName, userId);
@@ -1111,11 +1131,19 @@
      */
 
     private void addStateCallback(IVrStateCallbacks cb) {
-        mRemoteCallbacks.register(cb);
+        mVrStateRemoteCallbacks.register(cb);
     }
 
     private void removeStateCallback(IVrStateCallbacks cb) {
-        mRemoteCallbacks.unregister(cb);
+        mVrStateRemoteCallbacks.unregister(cb);
+    }
+
+    private void addPersistentStateCallback(IPersistentVrStateCallbacks cb) {
+        mPersistentVrStateRemoteCallbacks.register(cb);
+    }
+
+    private void removePersistentStateCallback(IPersistentVrStateCallbacks cb) {
+        mPersistentVrStateRemoteCallbacks.unregister(cb);
     }
 
     private boolean getVrMode() {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index e3941b9..16edd35 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -161,11 +161,6 @@
         } else {
             mClearProlongedAnimation = true;
         }
-
-        // Since we are finally starting our animation, we don't need the logic anymore to prevent
-        // the app from showing again if we just moved between stacks.
-        // See {@link WindowState#notifyMovedInStack}.
-        mAppToken.resetJustMovedInStack();
     }
 
     public void setDummyAnimation() {
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 c20ee97..111fbd3f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -55,6 +55,7 @@
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.IApplicationToken;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy.StartingSurface;
 
@@ -166,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,
@@ -365,6 +368,13 @@
                 mEnteringAnimation = true;
                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
             }
+            if (hidden && !delayed) {
+                SurfaceControl.openTransaction();
+                for (int i = mChildren.size() - 1; i >= 0; i--) {
+                    mChildren.get(i).mWinAnimator.hide("immediately hidden");
+                }
+                SurfaceControl.closeTransaction();
+            }
 
             if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) {
                 // The token is not closing nor opening, so even if there is an animation set, that
@@ -967,19 +977,6 @@
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
 
-    void resetJustMovedInStack() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            (mChildren.get(i)).resetJustMovedInStack();
-        }
-    }
-
-    void notifyMovedInStack() {
-        for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = mChildren.get(winNdx);
-            win.notifyMovedInStack();
-        }
-    }
-
     void setAppLayoutChanges(int changes, String reason) {
         if (!mChildren.isEmpty()) {
             final DisplayContent dc = getDisplayContent();
@@ -1175,7 +1172,12 @@
      */
     @Override
     int getOrientation() {
-        if (fillsParent() && (isVisible() || mService.mOpeningApps.contains(this))) {
+        // The {@link AppWindowToken} should only specify an orientation when it is not closing or
+        // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
+        // an Activity in another task being started in the wrong orientation during the transition.
+        if (fillsParent()
+                && !(sendingToBottom || mService.mClosingApps.contains(this))
+                && (isVisible() || mService.mOpeningApps.contains(this))) {
             return mOrientation;
         }
 
@@ -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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e5b00f3..01a992f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -179,11 +179,23 @@
     // Mapping from a token IBinder to a WindowToken object on this display.
     private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
 
+    // Initial display metrics.
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
     int mInitialDisplayDensity = 0;
+
+    /**
+     * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
+     * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
+     * @see WindowManagerService#setForcedDisplaySize(int, int, int)
+     */
     int mBaseDisplayWidth = 0;
     int mBaseDisplayHeight = 0;
+    /**
+     * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity}
+     * but can be set from Settings or via shell command "adb shell wm density".
+     * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int)
+     */
     int mBaseDisplayDensity = 0;
     boolean mDisplayScalingDisabled;
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -1511,6 +1523,10 @@
     void updateDisplayInfo() {
         mDisplay.getDisplayInfo(mDisplayInfo);
         mDisplay.getMetrics(mDisplayMetrics);
+
+        // Check if display metrics changed and update base values if needed.
+        updateBaseDisplayMetricsIfNeeded();
+
         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
             mTaskStackContainers.get(i).updateDisplayInfo(null);
         }
@@ -1526,10 +1542,11 @@
             }
         }
 
-        mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
-        mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
-        mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
-        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+        updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
+                mDisplayInfo.logicalDensityDpi);
+        mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+        mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+        mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
     }
 
     void getLogicalDisplayRect(Rect out) {
@@ -1559,6 +1576,50 @@
         }
     }
 
+    /**
+     * If display metrics changed, overrides are not set and it's not just a rotation - update base
+     * values.
+     */
+    private void updateBaseDisplayMetricsIfNeeded() {
+        final int orientation = mDisplayInfo.rotation;
+        final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
+        final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
+        final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
+        int density = mDisplayInfo.logicalDensityDpi;
+
+        boolean displayMetricsChanged = false;
+
+        // Check if display size is not forced and changed in new display info.
+        boolean isDisplaySizeForced = mBaseDisplayWidth != mInitialDisplayWidth
+                || mBaseDisplayHeight != mInitialDisplayHeight;
+        if (!isDisplaySizeForced) {
+            displayMetricsChanged = mBaseDisplayWidth != newWidth
+                    || mBaseDisplayHeight != newHeight;
+        }
+
+        // Check if display density is not forced and changed in new display info.
+        final int forcedDensity = mBaseDisplayDensity != mInitialDisplayDensity
+                ? mBaseDisplayDensity : 0;
+        if (forcedDensity != 0) {
+            density = forcedDensity;
+        } else {
+            displayMetricsChanged |= mBaseDisplayDensity != mDisplayInfo.logicalDensityDpi;
+        }
+
+        if (displayMetricsChanged) {
+            updateBaseDisplayMetrics(newWidth, newHeight, density);
+            mService.reconfigureDisplayLocked(this);
+        }
+    }
+
+    /** Update base (override) display metrics. */
+    void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
+        mBaseDisplayWidth = baseWidth;
+        mBaseDisplayHeight = baseHeight;
+        mBaseDisplayDensity = baseDensity;
+        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+    }
+
     void getContentRect(Rect out) {
         out.set(mContentRect);
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 99c085f..3ffb093 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
@@ -107,6 +108,9 @@
         setController(controller);
         setBounds(bounds, overrideConfig);
         mTaskDescription = taskDescription;
+
+        // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
+        setOrientation(SCREEN_ORIENTATION_UNSET);
     }
 
     DisplayContent getDisplayContent() {
@@ -208,10 +212,6 @@
     void positionAt(int position, Rect bounds, Configuration overrideConfig) {
         mStack.positionChildAt(position, this, false /* includingParents */);
         resizeLocked(bounds, overrideConfig, false /* force */);
-
-        for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
-            mChildren.get(activityNdx).notifyMovedInStack();
-        }
     }
 
     @Override
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/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5844b0b..dd2689b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5305,8 +5305,8 @@
                     if (displayContent.mBaseDisplayWidth != width
                             || displayContent.mBaseDisplayHeight != height) {
                         Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
-                        displayContent.mBaseDisplayWidth = width;
-                        displayContent.mBaseDisplayHeight = height;
+                        displayContent.updateBaseDisplayMetrics(width, height,
+                                displayContent.mBaseDisplayDensity);
                     }
                 } catch (NumberFormatException ex) {
                 }
@@ -5331,8 +5331,7 @@
     // displayContent must not be null
     private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
         Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
-        displayContent.mBaseDisplayWidth = width;
-        displayContent.mBaseDisplayHeight = height;
+        displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity);
         reconfigureDisplayLocked(displayContent);
     }
 
@@ -7306,4 +7305,49 @@
         mAppFreezeListeners.remove(listener);
     }
 
+    /**
+     * WARNING: This interrupts surface updates, be careful! Don't
+     * execute within the transaction for longer than you would
+     * execute on an animation thread.
+     * WARNING: This holds the WindowManager lock, so if exec will acquire
+     * the ActivityManager lock, you should hold it BEFORE calling this
+     * otherwise there is a risk of deadlock if another thread holding the AM
+     * lock waits on the WM lock.
+     * WARNING: This method contains locks known to the State of California
+     * to cause Deadlocks and other conditions.
+     *
+     *
+     * Begins a surface transaction with which the AM can batch operations.
+     * All Surface updates performed by the WindowManager following this
+     * will not appear on screen until after the call to
+     * closeSurfaceTransaction.
+     *
+     * ActivityManager can use this to ensure multiple 'commands' will all
+     * be reflected in a single frame. For example when reparenting a window
+     * which was previously hidden due to it's parent properties, we may
+     * need to ensure it is hidden in the same frame that the properties
+     * from the new parent are inherited, otherwise it could be revealed
+     * mistakenly.
+     *
+     *
+     * TODO(b/36393204): We can investigate totally replacing #deferSurfaceLayout
+     * with something like this but it seems that some existing cases of
+     * deferSurfaceLayout may be a little too broad, in particular the total
+     * enclosure of startActivityUnchecked which could run for quite some time.
+     */
+    public void inSurfaceTransaction(Runnable exec) {
+        // We hold the WindowManger lock to ensure relayoutWindow
+        // does not return while a Surface transaction is opening.
+        // The client depends on us to have resized the surface
+        // by that point (b/36462635)
+
+        synchronized (mWindowMap) {
+            SurfaceControl.openTransaction();
+            try {
+                exec.run();
+            } finally {
+                SurfaceControl.closeTransaction();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ca5d551..d4c8b1f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -517,11 +517,6 @@
     final private Rect mTmpRect = new Rect();
 
     /**
-     * See {@link #notifyMovedInStack}.
-     */
-    private boolean mJustMovedInStack;
-
-    /**
      * Whether the window was resized by us while it was gone for layout.
      */
     boolean mResizedWhileGone = false;
@@ -1998,49 +1993,6 @@
         }
     }
 
-    /**
-     * Notifies this window that the corresponding task has just moved in the stack.
-     * <p>
-     * This is used to fix the following: If we moved in the stack, and if the last clip rect was
-     * empty, meaning that our task was completely offscreen, we need to keep it invisible because
-     * the actual app transition that updates the visibility is delayed by a few transactions.
-     * Instead of messing around with the ordering and timing how transitions and transactions are
-     * executed, we introduce this little hack which prevents this window of getting visible again
-     * with the wrong bounds until the app transitions has started.
-     * <p>
-     * This method notifies the window about that we just moved in the stack so we can apply this
-     * logic in {@link WindowStateAnimator#updateSurfaceWindowCrop}
-     */
-    void notifyMovedInStack() {
-        mJustMovedInStack = true;
-
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState c = mChildren.get(i);
-            c.notifyMovedInStack();
-        }
-    }
-
-    /**
-     * See {@link #notifyMovedInStack}.
-     *
-     * @return Whether we just got moved in the corresponding stack.
-     */
-    boolean hasJustMovedInStack() {
-        return mJustMovedInStack;
-    }
-
-    /**
-     * Resets that we just moved in the corresponding stack. See {@link #notifyMovedInStack}.
-     */
-    void resetJustMovedInStack() {
-        mJustMovedInStack = false;
-
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowState c = mChildren.get(i);
-            c.resetJustMovedInStack();
-        }
-    }
-
     private final class DeadWindowEventReceiver extends InputEventReceiver {
         DeadWindowEventReceiver(InputChannel inputChannel) {
             super(inputChannel, mService.mH.getLooper());
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4b71338..48de7e4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1177,10 +1177,6 @@
 
         w.transformClipRectFromScreenToSurfaceSpace(clipRect);
 
-        // See {@link WindowState#notifyMovedInStack} for why this is necessary.
-        if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
-            clipRect.setEmpty();
-        }
         return true;
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2727465..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;
@@ -183,8 +183,6 @@
             "com.android.server.search.SearchManagerService$Lifecycle";
     private static final String THERMAL_OBSERVER_CLASS =
             "com.google.android.clockwork.ThermalObserver";
-    private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
-            "com.google.android.clockwork.bluetooth.WearBluetoothService";
     private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
             "com.google.android.clockwork.connectivity.WearConnectivityService";
     private static final String WEAR_TIME_SERVICE_CLASS =
@@ -1394,9 +1392,11 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("StartCompanionDeviceManager");
-            mSystemServiceManager.startService(COMPANION_DEVICE_MANAGER_SERVICE_CLASS);
-            traceEnd();
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP)) {
+                traceBeginAndSlog("StartCompanionDeviceManager");
+                mSystemServiceManager.startService(COMPANION_DEVICE_MANAGER_SERVICE_CLASS);
+                traceEnd();
+            }
 
             traceBeginAndSlog("StartRestrictionManager");
             mSystemServiceManager.startService(RestrictionsManagerService.class);
@@ -1479,10 +1479,6 @@
         }
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            traceBeginAndSlog("StartWearBluetooth");
-            mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
-            traceEnd();
-
             traceBeginAndSlog("StartWearConnectivityService");
             mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
             traceEnd();
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 472f984..43c38a6 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -69,6 +69,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
+import com.android.server.PreloadsFileCacheExpirationJobService;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.am.ActivityManagerService;
@@ -259,6 +260,7 @@
                         if (!deletePreloadsFolderContents()) {
                             Slog.w(TAG, "Failed to delete preloads folder contents");
                         }
+                        PreloadsFileCacheExpirationJobService.schedule(mInjector.getContext());
                     });
 
                     stopDemoMode();
@@ -443,6 +445,11 @@
                 mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
     }
 
+    /**
+     * Deletes contents of {@link Environment#getDataPreloadsDirectory()},
+     * but leave {@link Environment#getDataPreloadsFileCacheDirectory()}
+     * @return true if contents was sucessfully deleted
+     */
     private boolean deletePreloadsFolderContents() {
         final File dir = mInjector.getDataPreloadsDirectory();
         final File[] files = FileUtils.listFilesOrEmpty(dir);
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/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index f8a32bb..3dbd803 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -94,10 +94,12 @@
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
 
         NotificationRecord r = getNotificationRecord(channel);
+        int notificationImportance = r.getImportance();
 
         extractor.process(r);
 
-        assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_UNSPECIFIED);
+        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, r.getUserImportance());
+        assertEquals(notificationImportance, r.getImportance());
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 13d6c5d..946044d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -289,6 +289,18 @@
     }
 
     @Test
+    public void testImportance_locked_unspecified_preUpgrade() throws Exception {
+        defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
+        defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /*defaultLights */);
+
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
+    }
+
+    @Test
     public void testImportance_upgrade() throws Exception {
         StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
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 5a94018..40af2f8 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -208,6 +208,7 @@
     private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
         assertEquals(expected.getId(), actual.getId());
         assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getDescription(), actual.getDescription());
         assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
         assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
         assertEquals(expected.getImportance(), actual.getImportance());
@@ -283,6 +284,7 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+        channel2.setDescription("descriptions for all");
         channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel2.enableLights(true);
         channel2.setBypassDnd(true);
@@ -725,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/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 6cca771..a9c69f6 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -563,6 +563,14 @@
     }
 
     @Test
+    public void testSetActiveScorer_requestNetworkScoresPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mNetworkScoreService.setActiveScorer(null);
+    }
+
+    @Test
     public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() {
         bindToScorer(false /*callerIsScorer*/);
         when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
@@ -577,6 +585,36 @@
     }
 
     @Test
+    public void testDisableScoring_activeScorer_noRequestNetworkScoresPermission() {
+        bindToScorer(true /*callerIsScorer*/);
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        mNetworkScoreService.disableScoring();
+    }
+
+    @Test
+    public void testGetAllValidScorer_noRequestNetworkScoresPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        try {
+            mNetworkScoreService.getAllValidScorers();
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetAllValidScorer_requestNetworkScoresPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mNetworkScoreService.getAllValidScorers();
+    }
+
+    @Test
     public void testRegisterNetworkScoreCache_noRequestNetworkScoresPermission() {
         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
                 eq(permission.REQUEST_NETWORK_SCORES), anyString());
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index e433b60..308632f 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -24,6 +24,8 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.nullable;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -87,6 +89,17 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+
+/**
+ * Tests for {@link AccountManagerService}.
+ * <p>Run with:<pre>
+ * mmma -j40 frameworks/base/services/tests/servicestests
+ * adb install -r ${OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * adb shell am instrument -w -e class package com.android.server.accounts \
+ * com.android.frameworks.servicestests\
+ * /android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
 public class AccountManagerServiceTest extends AndroidTestCase {
     private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
     private static final long ONE_DAY_IN_MILLISECOND = 86400000;
@@ -103,6 +116,8 @@
 
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
     @Captor private ArgumentCaptor<Bundle> mBundleCaptor;
+    private int mVisibleAccountsChangedBroadcasts;
+    private int mLoginAccountsChangedBroadcasts;
 
     private static final int LATCH_TIMEOUT_MS = 500;
     private static final String PREN_DB = "pren.db";
@@ -1042,7 +1057,7 @@
         waitForLatch(latch);
         // Verify notification is cancelled
         verify(mMockNotificationManager).cancelNotificationWithTag(
-                anyString(), anyString(), anyInt(), anyInt());
+                anyString(), nullable(String.class), anyInt(), anyInt());
 
         verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
         Bundle result = mBundleCaptor.getValue();
@@ -1889,7 +1904,7 @@
         waitForLatch(latch);
         // Verify notification is cancelled
         verify(mMockNotificationManager).cancelNotificationWithTag(
-                anyString(), anyString(), anyInt(), anyInt());
+                anyString(), nullable(String.class), anyInt(), anyInt());
 
         verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
         Bundle result = mBundleCaptor.getValue();
@@ -2446,6 +2461,161 @@
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
     }
 
+    @SmallTest
+    public void testRegisterAccountListener() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+
+        mAms.registerAccountListener(
+            null, //accountTypes
+            "testpackage"); // opPackageName
+
+        // Check that two previously registered receivers can be unregistered successfully.
+        mAms.unregisterAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+
+        mAms.unregisterAccountListener(
+             null, //accountTypes
+            "testpackage"); // opPackageName
+    }
+
+    @SmallTest
+    public void testRegisterAccountListenerAndAddAccount() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+
+        mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+        // Notification about new account
+        updateBroadcastCounters(2);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 1);
+        assertEquals(mLoginAccountsChangedBroadcasts, 1);
+    }
+
+    @SmallTest
+    public void testRegisterAccountListenerAndAddAccountOfDifferentType() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2},
+            "testpackage"); // opPackageName
+
+        mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+        mAms.addAccountExplicitly(
+            AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p11", null);
+        // Notification about new account
+
+        updateBroadcastCounters(2);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 0); // broadcast was not sent
+        assertEquals(mLoginAccountsChangedBroadcasts, 2);
+    }
+
+    @SmallTest
+    public void testRegisterAccountListenerWithAddingTwoAccounts() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+        mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+        mAms.unregisterAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+        mAms.addAccountExplicitly(
+            AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p11", null);
+
+        updateBroadcastCounters(3);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 1);
+        assertEquals(mLoginAccountsChangedBroadcasts, 2);
+
+        mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS);
+        mAms.registerAccountListener( null /* accountTypes */, "testpackage");
+        mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE);
+
+        updateBroadcastCounters(6);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 2);
+        assertEquals(mLoginAccountsChangedBroadcasts, 4);
+    }
+
+    @SmallTest
+    public void testRegisterAccountListenerForThreePackages() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage1"); // opPackageName
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage2"); // opPackageName
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage3"); // opPackageName
+        mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+        updateBroadcastCounters(4);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 3);
+        assertEquals(mLoginAccountsChangedBroadcasts, 1);
+
+        mAms.unregisterAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage3"); // opPackageName
+        // Remove account with 2 active listeners.
+        mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS);
+        updateBroadcastCounters(7);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 5);
+        assertEquals(mLoginAccountsChangedBroadcasts, 2); // 3 add, 2 remove
+
+        // Add account of another type.
+        mAms.addAccountExplicitly(
+            AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS_TYPE_2, "p11", null);
+
+        updateBroadcastCounters(8);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 5);
+        assertEquals(mLoginAccountsChangedBroadcasts, 3);
+    }
+
+    @SmallTest
+    public void testRegisterAccountListenerCredentialsUpdate() throws Exception {
+        unlockSystemUser();
+        mAms.registerAccountListener(
+            new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+            "testpackage"); // opPackageName
+        mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+        mAms.setPassword(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "pwd");
+        updateBroadcastCounters(4);
+        assertEquals(mVisibleAccountsChangedBroadcasts, 2);
+        assertEquals(mLoginAccountsChangedBroadcasts, 2);
+    }
+
+    @SmallTest
+    public void testUnregisterAccountListenerNotRegistered() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.unregisterAccountListener(
+                new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+                "testpackage"); // opPackageName
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+            // IllegalArgumentException is expected.
+        }
+    }
+
+    private void updateBroadcastCounters (int expectedBroadcasts){
+        mVisibleAccountsChangedBroadcasts = 0;
+        mLoginAccountsChangedBroadcasts = 0;
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockContext, times(expectedBroadcasts)).sendBroadcastAsUser(captor.capture(),
+            any(UserHandle.class));
+        for (Intent intent : captor.getAllValues()) {
+            if (AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED. equals(intent.getAction())) {
+                mVisibleAccountsChangedBroadcasts++;
+            }
+            if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION. equals(intent.getAction())) {
+                mLoginAccountsChangedBroadcasts++;
+            }
+        }
+    }
+
     private void waitForLatch(CountDownLatch latch) {
         try {
             latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
index 614680e..d176a0d 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -73,6 +73,8 @@
             new Account(ACCOUNT_NAME_INTERVENE, ACCOUNT_TYPE_1);
     public static final Account ACCOUNT_ERROR =
             new Account(ACCOUNT_NAME_ERROR, ACCOUNT_TYPE_1);
+    public static final Account ACCOUNT_SUCCESS_TYPE_2 =
+            new Account(ACCOUNT_NAME_SUCCESS, ACCOUNT_TYPE_2);
 
     public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
     public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
@@ -81,4 +83,4 @@
         "com.android.server.accounts.account_manager_service_test.error.message";
 
     private AccountManagerServiceTestFixtures() {}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
index d18457b..ce5b8cb 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -33,6 +33,8 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.RetailDemoModeServiceInternal;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -97,6 +99,7 @@
     private @Mock AudioManager mAudioManager;
     private @Mock WifiManager mWifiManager;
     private @Mock LockPatternUtils mLockPatternUtils;
+    private @Mock JobScheduler mJobScheduler;
     private MockPreloadAppsInstaller mPreloadAppsInstaller;
     private MockContentResolver mContentResolver;
     private MockContactsProvider mContactsProvider;
@@ -110,6 +113,12 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        Context originalContext = InstrumentationRegistry.getContext();
+        when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
+        when(mContext.getResources()).thenReturn(originalContext.getResources());
+        when(mContext.getSystemServiceName(eq(JobScheduler.class))).thenReturn(
+                Context.JOB_SCHEDULER_SERVICE);
+        when(mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(mJobScheduler);
         mContentResolver = new MockContentResolver(mContext);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         mContactsProvider = new MockContactsProvider(mContext);
@@ -218,6 +227,8 @@
         // verify that the preloaded directory is emptied.
         assertEquals("Preloads directory is not emptied",
                 0, mTestPreloadsDir.list().length);
+        // Verify that the expiration job was scheduled
+        verify(mJobScheduler).schedule(any(JobInfo.class));
     }
 
     @Test
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/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 1c69033..3ce3df1 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import android.content.pm.ActivityInfo;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -23,6 +26,9 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -58,6 +64,42 @@
     }
 
     @Test
+    public void testClosingAppDifferentStackOrientation() throws Exception {
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final Task task1 = createTaskInStack(stack, 0 /* userId */);
+        TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+        task1.addChild(appWindowToken1, 0);
+        appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        final Task task2 = createTaskInStack(stack, 1 /* userId */);
+        TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+        task2.addChild(appWindowToken2, 0);
+        appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+        assertEquals(stack.getOrientation(), SCREEN_ORIENTATION_PORTRAIT);
+        sWm.mClosingApps.add(appWindowToken2);
+        assertEquals(stack.getOrientation(), SCREEN_ORIENTATION_LANDSCAPE);
+    }
+
+    @Test
+    public void testMoveTaskToBackDifferentStackOrientation() throws Exception {
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final Task task1 = createTaskInStack(stack, 0 /* userId */);
+        TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+        task1.addChild(appWindowToken1, 0);
+        appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        final Task task2 = createTaskInStack(stack, 1 /* userId */);
+        TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+        task2.addChild(appWindowToken2, 0);
+        appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+        assertEquals(stack.getOrientation(), SCREEN_ORIENTATION_PORTRAIT);
+        task2.setSendingToBottom(true);
+        assertEquals(stack.getOrientation(), SCREEN_ORIENTATION_LANDSCAPE);
+    }
+
+    @Test
     public void testStackRemoveImmediately() throws Exception {
         final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
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/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 199a12a..bc5e4d5 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1897,7 +1897,7 @@
         number = extractNetworkPortionAlt(number);
 
         String emergencyNumbers = "";
-        int slotId = SubscriptionManager.getSlotId(subId);
+        int slotId = SubscriptionManager.getSlotIndex(subId);
 
         // retrieve the list of emergency numbers
         // check read-write ecclist property first
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index dd6f9cb..201f3ad 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -521,14 +521,14 @@
     }
 
     /**
-     * Get the active SubscriptionInfo associated with the slotIdx
-     * @param slotIdx the slot which the subscription is inserted
+     * Get the active SubscriptionInfo associated with the slotIndex
+     * @param slotIndex the slot which the subscription is inserted
      * @return SubscriptionInfo, maybe null if its not active
      */
-    public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) {
-        if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx);
-        if (!isValidSlotId(slotIdx)) {
-            logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx");
+    public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
+        if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex);
+        if (!isValidSlotIndex(slotIndex)) {
+            logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIndex");
             return null;
         }
 
@@ -537,7 +537,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx,
+                result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
                         mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
@@ -671,24 +671,24 @@
     /**
      * Add a new SubscriptionInfo to SubscriptionInfo database if needed
      * @param iccId the IccId of the SIM card
-     * @param slotId the slot which the SIM is inserted
+     * @param slotIndex the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
      * @hide
      */
-    public Uri addSubscriptionInfoRecord(String iccId, int slotId) {
-        if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+    public Uri addSubscriptionInfoRecord(String iccId, int slotIndex) {
+        if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotIndex:" + slotIndex);
         if (iccId == null) {
             logd("[addSubscriptionInfoRecord]- null iccId");
         }
-        if (!isValidSlotId(slotId)) {
-            logd("[addSubscriptionInfoRecord]- invalid slotId");
+        if (!isValidSlotIndex(slotIndex)) {
+            logd("[addSubscriptionInfoRecord]- invalid slotIndex");
         }
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
                 // FIXME: This returns 1 on success, 0 on error should should we return it?
-                iSub.addSubInfoRecord(iccId, slotId);
+                iSub.addSubInfoRecord(iccId, slotIndex);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -830,15 +830,15 @@
     }
 
     /**
-     * Get slotId associated with the subscription.
-     * @return slotId as a positive integer or a negative value if an error either
+     * Get slotIndex associated with the subscription.
+     * @return slotIndex as a positive integer or a negative value if an error either
      * SIM_NOT_INSERTED or < 0 if an invalid slot index
      * @hide
      */
-    public static int getSlotId(int subId) {
+    public static int getSlotIndex(int subId) {
         if (!isValidSubscriptionId(subId)) {
             if (DBG) {
-                logd("[getSlotId]- fail");
+                logd("[getSlotIndex]- fail");
             }
         }
 
@@ -847,7 +847,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSlotId(subId);
+                result = iSub.getSlotIndex(subId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -858,8 +858,8 @@
     }
 
     /** @hide */
-    public static int[] getSubId(int slotId) {
-        if (!isValidSlotId(slotId)) {
+    public static int[] getSubId(int slotIndex) {
+        if (!isValidSlotIndex(slotIndex)) {
             logd("[getSubId]- fail");
             return null;
         }
@@ -869,7 +869,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subId = iSub.getSubId(slotId);
+                subId = iSub.getSubId(slotIndex);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1155,8 +1155,8 @@
     }
 
     /** @hide */
-    public static boolean isValidSlotId(int slotId) {
-        return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount();
+    public static boolean isValidSlotIndex(int slotIndex) {
+        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
     }
 
     /** @hide */
@@ -1179,7 +1179,7 @@
         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
-        //FIXME this is using phoneId and slotId interchangeably
+        //FIXME this is using phoneId and slotIndex interchangeably
         //Eventually, this should be removed as it is not the slot id
         intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
     }
@@ -1228,9 +1228,9 @@
     }
 
     /**
-     * Returns a constant indicating the state of sim for the slot idx.
+     * Returns a constant indicating the state of sim for the slot index.
      *
-     * @param slotIdx
+     * @param slotIndex
      *
      * {@See TelephonyManager#SIM_STATE_UNKNOWN}
      * {@See TelephonyManager#SIM_STATE_ABSENT}
@@ -1244,13 +1244,13 @@
      *
      * {@hide}
      */
-    public static int getSimStateForSlotIdx(int slotIdx) {
+    public static int getSimStateForSlotIndex(int slotIndex) {
         int simState = TelephonyManager.SIM_STATE_UNKNOWN;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                simState = iSub.getSimStateForSlotIdx(slotIdx);
+                simState = iSub.getSimStateForSlotIndex(slotIndex);
             }
         } catch (RemoteException ex) {
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4dda766..0eaa359 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -918,15 +918,15 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @param slotId of which deviceID is returned
+     * @param slotIndex of which deviceID is returned
      */
     /** {@hide} */
-    public String getDeviceSoftwareVersion(int slotId) {
+    public String getDeviceSoftwareVersion(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
 
         try {
-            return telephony.getDeviceSoftwareVersionForSlot(slotId, getOpPackageName());
+            return telephony.getDeviceSoftwareVersionForSlot(slotIndex, getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -961,15 +961,15 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @param slotId of which deviceID is returned
+     * @param slotIndex of which deviceID is returned
      */
-    public String getDeviceId(int slotId) {
-        // FIXME this assumes phoneId == slotId
+    public String getDeviceId(int slotIndex) {
+        // FIXME this assumes phoneId == slotIndex
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName());
+            return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -996,17 +996,17 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @param slotId of which deviceID is returned
+     * @param slotIndex of which deviceID is returned
      *
      * @hide
      */
     @SystemApi
-    public String getImei(int slotId) {
+    public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
 
         try {
-            return telephony.getImeiForSlot(slotId, getOpPackageName());
+            return telephony.getImeiForSlot(slotIndex, getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1026,11 +1026,11 @@
     /**
      * Returns the NAI. Return null if NAI is not available.
      *
-     *  @param slotId of which Nai is returned
+     *  @param slotIndex of which Nai is returned
      */
     /** {@hide}*/
-    public String getNai(int slotId) {
-        int[] subId = SubscriptionManager.getSubId(slotId);
+    public String getNai(int slotIndex) {
+        int[] subId = SubscriptionManager.getSubId(slotIndex);
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
@@ -1226,23 +1226,23 @@
      *
      * @hide
      */
-    public int getCurrentPhoneTypeForSlot(int slotId) {
+    public int getCurrentPhoneTypeForSlot(int slotIndex) {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getActivePhoneTypeForSlot(slotId);
+                return telephony.getActivePhoneTypeForSlot(slotIndex);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
-                return getPhoneTypeFromProperty(slotId);
+                return getPhoneTypeFromProperty(slotIndex);
             }
         } catch (RemoteException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty(slotId);
+            return getPhoneTypeFromProperty(slotIndex);
         } catch (NullPointerException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty(slotId);
+            return getPhoneTypeFromProperty(slotIndex);
         }
     }
 
@@ -1962,17 +1962,17 @@
     /**
      * @return true if a ICC card is present for a subscription
      *
-     * @param slotId for which icc card presence is checked
+     * @param slotIndex for which icc card presence is checked
      */
     /** {@hide} */
-    // FIXME Input argument slotId should be of type int
-    public boolean hasIccCard(int slotId) {
+    // FIXME Input argument slotIndex should be of type int
+    public boolean hasIccCard(int slotIndex) {
 
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return false;
-            return telephony.hasIccCardUsingSlotId(slotId);
+            return telephony.hasIccCardUsingSlotIndex(slotIndex);
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return false;
@@ -1997,31 +1997,31 @@
      * @see #SIM_STATE_CARD_RESTRICTED
      */
     public int getSimState() {
-        int slotIdx = getDefaultSim();
-        // slotIdx may be invalid due to sim being absent. In that case query all slots to get
+        int slotIndex = getDefaultSim();
+        // slotIndex may be invalid due to sim being absent. In that case query all slots to get
         // sim state
-        if (slotIdx < 0) {
+        if (slotIndex < 0) {
             // query for all slots and return absent if all sim states are absent, otherwise
             // return unknown
             for (int i = 0; i < getPhoneCount(); i++) {
                 int simState = getSimState(i);
                 if (simState != SIM_STATE_ABSENT) {
-                    Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", sim state for " +
-                            "slotIdx=" + i + " is " + simState + ", return state as unknown");
+                    Rlog.d(TAG, "getSimState: default sim:" + slotIndex + ", sim state for " +
+                            "slotIndex=" + i + " is " + simState + ", return state as unknown");
                     return SIM_STATE_UNKNOWN;
                 }
             }
-            Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", all SIMs absent, return " +
+            Rlog.d(TAG, "getSimState: default sim:" + slotIndex + ", all SIMs absent, return " +
                     "state as absent");
             return SIM_STATE_ABSENT;
         }
-        return getSimState(slotIdx);
+        return getSimState(slotIndex);
     }
 
     /**
      * Returns a constant indicating the state of the device SIM card in a slot.
      *
-     * @param slotIdx
+     * @param slotIndex
      *
      * @see #SIM_STATE_UNKNOWN
      * @see #SIM_STATE_ABSENT
@@ -2034,8 +2034,8 @@
      * @see #SIM_STATE_CARD_IO_ERROR
      * @see #SIM_STATE_CARD_RESTRICTED
      */
-    public int getSimState(int slotIdx) {
-        int simState = SubscriptionManager.getSimStateForSlotIdx(slotIdx);
+    public int getSimState(int slotIndex) {
+        int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
         return simState;
     }
 
@@ -3210,12 +3210,12 @@
      *
      * @hide
      */
-    public int getCallStateForSlot(int slotId) {
+    public int getCallStateForSlot(int slotIndex) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return CALL_STATE_IDLE;
-            return telephony.getCallStateForSlot(slotId);
+            return telephony.getCallStateForSlot(slotIndex);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return CALL_STATE_IDLE;
@@ -4033,7 +4033,7 @@
 
     /** {@hide} */
     public int getDefaultSim() {
-        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubscriptionId());
+        return SubscriptionManager.getSlotIndex(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /**
@@ -4398,7 +4398,7 @@
      * feature or {@link null} if the service is not available. If an ImsServiceController is
      * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
      * feature updates.
-     * @param slotId The SIM slot that we are requesting the {@link IImsServiceController} for.
+     * @param slotIndex The SIM slot that we are requesting the {@link IImsServiceController} for.
      * @param feature The IMS Feature we are requesting, corresponding to {@link ImsFeature}.
      * @param callback Listener that will send updates to ImsManager when there are updates to
      * ImsServiceController.
@@ -4406,12 +4406,12 @@
      * it is unavailable.
      * @hide
      */
-    public IImsServiceController getImsServiceControllerAndListen(int slotId, @Feature int feature,
+    public IImsServiceController getImsServiceControllerAndListen(int slotIndex, @Feature int feature,
             IImsServiceFeatureListener callback) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getImsServiceControllerAndListen(slotId, feature, callback);
+                return telephony.getImsServiceControllerAndListen(slotIndex, feature, callback);
             }
         } catch (RemoteException e) {
             Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage());
@@ -5641,7 +5641,7 @@
     /**
      * Set SIM card power state. Request is equivalent to inserting or removing the card.
      *
-     * @param slotId SIM slot id
+     * @param slotIndex SIM slot id
      * @param powerUp True if powering up the SIM, otherwise powering down
      *
      * <p>Requires Permission:
@@ -5649,11 +5649,11 @@
      *
      * @hide
      **/
-    public void setSimPowerStateForSlot(int slotId, boolean powerUp) {
+    public void setSimPowerStateForSlot(int slotIndex, boolean powerUp) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                telephony.setSimPowerStateForSlot(slotId, powerUp);
+                telephony.setSimPowerStateForSlot(slotIndex, powerUp);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
@@ -6237,7 +6237,7 @@
     }
 
     /**
-     * Set the allowed carrier list for slotId
+     * Set the allowed carrier list for slotIndex
      * Require system privileges. In the future we may add this to carrier APIs.
      *
      * <p>Requires Permission:
@@ -6251,11 +6251,11 @@
      * @hide
      */
     @SystemApi
-    public int setAllowedCarriers(int slotId, List<CarrierIdentifier> carriers) {
+    public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.setAllowedCarriers(slotId, carriers);
+                return service.setAllowedCarriers(slotIndex, carriers);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
@@ -6266,7 +6266,7 @@
     }
 
     /**
-     * Get the allowed carrier list for slotId.
+     * Get the allowed carrier list for slotIndex.
      * Require system privileges. In the future we may add this to carrier APIs.
      *
      * <p>Requires Permission:
@@ -6280,11 +6280,11 @@
      * @hide
      */
     @SystemApi
-    public List<CarrierIdentifier> getAllowedCarriers(int slotId) {
+    public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.getAllowedCarriers(slotId);
+                return service.getAllowedCarriers(slotIndex);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index f6aef08..71f2c6b 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -52,12 +52,12 @@
     SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage);
 
     /**
-     * Get the active SubscriptionInfo associated with the slotIdx
-     * @param slotIdx the slot which the subscription is inserted
+     * Get the active SubscriptionInfo associated with the slotIndex
+     * @param slotIndex the slot which the subscription is inserted
      * @param callingPackage The package maing the call.
      * @return SubscriptionInfo, maybe null if its not active
      */
-    SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx, String callingPackage);
+    SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String callingPackage);
 
     /**
      * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted
@@ -96,10 +96,10 @@
     /**
      * Add a new SubscriptionInfo to subinfo database if needed
      * @param iccId the IccId of the SIM card
-     * @param slotId the slot which the SIM is inserted
+     * @param slotIndex the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
      */
-    int addSubInfoRecord(String iccId, int slotId);
+    int addSubInfoRecord(String iccId, int slotIndex);
 
     /**
      * Set SIM icon tint color by simInfo index
@@ -142,9 +142,9 @@
      */
     int setDataRoaming(int roaming, int subId);
 
-    int getSlotId(int subId);
+    int getSlotIndex(int subId);
 
-    int[] getSubId(int slotId);
+    int[] getSubId(int slotIndex);
 
     int getDefaultSubId();
 
@@ -177,10 +177,10 @@
     String getSubscriptionProperty(int subId, String propKey, String callingPackage);
 
     /**
-     * Get the SIM state for the slot idx
+     * Get the SIM state for the slot index
      * @return SIM state as the ordinal of IccCardConstants.State
      */
-    int getSimStateForSlotIdx(int slotIdx);
+    int getSimStateForSlotIndex(int slotIndex);
 
     boolean isActiveSubId(int subId);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 40d1dbb..9d12c24 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -381,7 +381,7 @@
     /**
      * Returns the call state for a slot.
      */
-     int getCallStateForSlot(int slotId);
+     int getCallStateForSlot(int slotIndex);
 
      int getDataActivity();
      int getDataState();
@@ -397,9 +397,9 @@
      * Returns the current active phone type as integer for particular slot.
      * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
      * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
-     * @param slotId - slot to query.
+     * @param slotIndex - slot to query.
      */
-    int getActivePhoneTypeForSlot(int slotId);
+    int getActivePhoneTypeForSlot(int slotIndex);
 
     /**
      * Returns the CDMA ERI icon index to display
@@ -573,10 +573,10 @@
 
     /**
      * Return true if an ICC card is present for a subId.
-     * @param slotId user preferred slotId.
+     * @param slotIndex user preferred slotIndex.
      * Return true if an ICC card is present
      */
-    boolean hasIccCardUsingSlotId(int slotId);
+    boolean hasIccCardUsingSlotIndex(int slotIndex);
 
     /**
      * Return if the current radio is LTE on CDMA. This
@@ -777,7 +777,7 @@
      *  requested as well as registering the ImsServiceController for callbacks using the
      *  IImsServiceFeatureListener interface.
      */
-    IImsServiceController getImsServiceControllerAndListen(int slotId, int feature,
+    IImsServiceController getImsServiceControllerAndListen(int slotIndex, int feature,
                 IImsServiceFeatureListener callback);
 
     /**
@@ -1085,22 +1085,22 @@
     /**
      * Returns the IMEI for the given slot.
      *
-     * @param slotId - device slot.
+     * @param slotIndex - device slot.
      * @param callingPackage The package making the call.
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    String getImeiForSlot(int slotId, String callingPackage);
+    String getImeiForSlot(int slotIndex, String callingPackage);
 
     /**
      * Returns the device software version.
      *
-     * @param slotId - device slot.
+     * @param slotIndex - device slot.
      * @param callingPackage The package making the call.
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    String getDeviceSoftwareVersionForSlot(int slotId, String callingPackage);
+    String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage);
 
     /**
      * Returns the subscription ID associated with the specified PhoneAccount.
@@ -1226,22 +1226,22 @@
     List<TelephonyHistogram> getTelephonyHistograms();
 
     /**
-     * Set the allowed carrier list for slotId
+     * Set the allowed carrier list for slotIndex
      * Require system privileges. In the future we may add this to carrier APIs.
      *
      * @return The number of carriers set successfully. Should match length of
      * carriers on success.
      */
-    int setAllowedCarriers(int slotId, in List<CarrierIdentifier> carriers);
+    int setAllowedCarriers(int slotIndex, in List<CarrierIdentifier> carriers);
 
     /**
-     * Get the allowed carrier list for slotId.
+     * Get the allowed carrier list for slotIndex.
      * Require system privileges. In the future we may add this to carrier APIs.
      *
      * @return List of {@link android.service.carrier.CarrierIdentifier}; empty list
      * means all carriers are allowed.
      */
-    List<CarrierIdentifier> getAllowedCarriers(int slotId);
+    List<CarrierIdentifier> getAllowedCarriers(int slotIndex);
 
     /**
      * Action set from carrier signalling broadcast receivers to enable/disable metered apns
@@ -1288,11 +1288,11 @@
 
     /**
      * Set SIM card power state. Request is equivalent to inserting or removing the card.
-     * @param slotId SIM slot id
+     * @param slotIndex SIM slot id
      * @param powerUp True if powering up the SIM, otherwise powering down
      * @hide
      * */
-    void setSimPowerStateForSlot(int slotId, boolean powerUp);
+    void setSimPowerStateForSlot(int slotIndex, boolean powerUp);
 
     /**
      * Returns a list of Forbidden PLMNs from the specified SIM App
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/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index aaff5d5..3bab4ac 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -26,6 +26,7 @@
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.content.res.BridgeAssetManager;
+import android.text.FontConfig;
 
 import java.awt.Font;
 import java.awt.FontFormatException;
@@ -43,6 +44,7 @@
 import java.util.Scanner;
 import java.util.Set;
 
+import static android.graphics.Typeface.Builder.RESOLVE_BY_FONT_TABLE;
 import static android.graphics.Typeface_Delegate.SYSTEM_FONTS;
 
 /**
@@ -247,12 +249,13 @@
 
     // ---- delegate methods ----
     @LayoutlibDelegate
-    /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex) {
+    /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex,
+            FontConfig.Axis[] axes, int weight, int italic) {
         if (thisFontFamily.mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFont after freezing.");
         }
         final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mBuilderPtr);
-        return delegate != null && delegate.addFont(path, ttcIndex);
+        return delegate != null && delegate.addFont(path, ttcIndex, weight, italic);
     }
 
     // ---- native methods ----
@@ -285,39 +288,41 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) {
-        assert false : "The only client of this method has been overriden.";
+    /*package*/ static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex,
+            int weight, int isItalic) {
+        assert false : "The only client of this method has been overridden.";
         return false;
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, int weight, boolean isItalic) {
-        assert false : "The only client of this method has been overriden.";
+            int ttcIndex, int weight, int isItalic) {
+        assert false : "The only client of this method has been overridden.";
         return false;
     }
 
     @LayoutlibDelegate
     /*package*/ static void nAddAxisValue(long builderPtr, int tag, float value) {
-        assert false : "The only client of this method has been overriden.";
+        assert false : "The only client of this method has been overridden.";
     }
 
     static boolean addFont(long builderPtr, final String path, final int weight,
             final boolean isItalic) {
         final FontFamily_Delegate delegate = getDelegate(builderPtr);
+        int italic = isItalic ? 1 : 0;
         if (delegate != null) {
             if (sFontLocation == null) {
-                delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, isItalic));
+                delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, italic));
                 return true;
             }
-            return delegate.addFont(path, weight, isItalic);
+            return delegate.addFont(path, weight, italic);
         }
         return false;
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean nAddFontFromAssetManager(long builderPtr, AssetManager mgr, String path,
-            int cookie, boolean isAsset, int weight, boolean isItalic) {
+            int cookie, boolean isAsset, int ttcIndex, int weight, int isItalic) {
         FontFamily_Delegate ffd = sManager.getDelegate(builderPtr);
         if (ffd == null) {
             return false;
@@ -358,12 +363,13 @@
                 Font font = Font.createFont(Font.TRUETYPE_FONT, fontStream);
                 fontInfo = new FontInfo();
                 fontInfo.mFont = font;
-                if (weight == 0) {
+                if (weight == RESOLVE_BY_FONT_TABLE) {
                     fontInfo.mWeight = font.isBold() ? BOLD_FONT_WEIGHT : DEFAULT_FONT_WEIGHT;
                 } else {
                     fontInfo.mWeight = weight;
                 }
-                fontInfo.mIsItalic = weight == 0 ? font.isItalic() : isItalic;
+                fontInfo.mIsItalic = isItalic == RESOLVE_BY_FONT_TABLE ? font.isItalic() :
+                        isItalic == 1;
                 ffd.addFont(fontInfo);
                 return true;
             } catch (IOException e) {
@@ -412,20 +418,20 @@
         mPostInitRunnables = null;
     }
 
-    private boolean addFont(final String path, int ttcIndex) {
+    private boolean addFont(final String path, int ttcIndex, int weight, int italic) {
         // FIXME: support ttc fonts. Hack JRE??
         if (sFontLocation == null) {
-            mPostInitRunnables.add(() -> addFont(path));
+            mPostInitRunnables.add(() -> addFont(path, weight, italic));
             return true;
         }
-        return addFont(path);
+        return addFont(path, weight, italic);
     }
 
      private boolean addFont(@NonNull String path) {
-         return addFont(path, DEFAULT_FONT_WEIGHT, path.endsWith(FONT_SUFFIX_ITALIC));
+         return addFont(path, DEFAULT_FONT_WEIGHT, path.endsWith(FONT_SUFFIX_ITALIC) ? 1 : RESOLVE_BY_FONT_TABLE);
      }
 
-    private boolean addFont(@NonNull String path, int weight, boolean isItalic) {
+    private boolean addFont(@NonNull String path, int weight, int italic) {
         if (path.startsWith(SYSTEM_FONTS) &&
                 !SDK_FONTS.contains(path.substring(SYSTEM_FONTS.length()))) {
             return mValid = false;
@@ -439,7 +445,7 @@
         FontInfo fontInfo = new FontInfo();
         fontInfo.mFont = font;
         fontInfo.mWeight = weight;
-        fontInfo.mIsItalic = isItalic;
+        fontInfo.mIsItalic = italic == RESOLVE_BY_FONT_TABLE ? font.isItalic() : italic == 1;
         addFont(fontInfo);
         return true;
     }
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>