Merge "fix ActivityMetricsLogger counter names"
diff --git a/Android.mk b/Android.mk
index d3e1cf5..aff6cf2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -226,7 +226,6 @@
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
 	core/java/android/service/gatekeeper/IGateKeeperService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
-	core/java/android/service/notification/INotificationAssistant.aidl \
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
 	core/java/android/service/notification/IConditionProvider.aidl \
diff --git a/api/current.txt b/api/current.txt
index 3854b7a..2f0c706 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4082,11 +4082,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -9568,8 +9571,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9581,13 +9584,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -33491,20 +33498,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33524,6 +33524,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
diff --git a/api/system-current.txt b/api/system-current.txt
index 2990516..81831f87 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4202,11 +4202,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -9884,8 +9887,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9897,7 +9900,7 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
     field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
@@ -9938,9 +9941,13 @@
     field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -35633,20 +35640,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -35666,6 +35666,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
diff --git a/api/test-current.txt b/api/test-current.txt
index 83d12fc..c155278 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4082,11 +4082,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -9568,8 +9571,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9581,13 +9584,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -33494,20 +33501,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33527,6 +33527,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 3fbbdff..8d7f347 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
@@ -35,95 +38,126 @@
 
 /**
  * A simple dialog containing an {@link android.widget.DatePicker}.
- *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
  */
 public class DatePickerDialog extends AlertDialog implements OnClickListener,
         OnDateChangedListener {
-
     private static final String YEAR = "year";
     private static final String MONTH = "month";
     private static final String DAY = "day";
 
     private final DatePicker mDatePicker;
-    private final OnDateSetListener mDateSetListener;
     private final Calendar mCalendar;
 
+    private OnDateSetListener mDateSetListener;
+
     private boolean mTitleNeedsUpdate = true;
 
     /**
-     * The callback used to indicate the user is done filling in the date.
+     * Creates a new date picker dialog for the current date using the parent
+     * context's default date picker dialog theme.
+     *
+     * @param context the parent context
      */
-    public interface OnDateSetListener {
-
-        /**
-         * @param view The view associated with this listener.
-         * @param year The year that was set.
-         * @param monthOfYear The month that was set (0-11) for compatibility
-         *  with {@link java.util.Calendar}.
-         * @param dayOfMonth The day of the month that was set.
-         */
-        void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
+    public DatePickerDialog(Context context) {
+        this(context, 0);
     }
 
     /**
-     * @param context The context the dialog is to run in.
-     * @param callBack How the parent is notified that the date is set.
-     * @param year The initial year of the dialog.
-     * @param monthOfYear The initial month of the dialog.
-     * @param dayOfMonth The initial day of the dialog.
+     * Creates a new date picker dialog for the current date.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
      */
-    public DatePickerDialog(Context context,
-            OnDateSetListener callBack,
-            int year,
-            int monthOfYear,
-            int dayOfMonth) {
-        this(context, 0, callBack, year, monthOfYear, dayOfMonth);
-    }
-
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == 0) {
-            final TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
-            return outValue.resourceId;
-        } else {
-            return resid;
-        }
-    }
-
-    /**
-     * @param context The context the dialog is to run in.
-     * @param theme the theme to apply to this dialog
-     * @param listener How the parent is notified that the date is set.
-     * @param year The initial year of the dialog.
-     * @param monthOfYear The initial month of the dialog.
-     * @param dayOfMonth The initial day of the dialog.
-     */
-    public DatePickerDialog(Context context, int theme, OnDateSetListener listener, int year,
-            int monthOfYear, int dayOfMonth) {
-        super(context, resolveDialogTheme(context, theme));
-
-        mDateSetListener = listener;
-        mCalendar = Calendar.getInstance();
+    public DatePickerDialog(Context context, @StyleRes int themeResId) {
+        super(context, resolveDialogTheme(context, themeResId));
 
         final Context themeContext = getContext();
         final LayoutInflater inflater = LayoutInflater.from(themeContext);
         final View view = inflater.inflate(R.layout.date_picker_dialog, null);
         setView(view);
+
         setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
         setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
         setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
 
+        mCalendar = Calendar.getInstance();
+
+        final int year = mCalendar.get(Calendar.YEAR);
+        final int monthOfYear = mCalendar.get(Calendar.MONTH);
+        final int dayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH);
         mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
         mDatePicker.init(year, monthOfYear, dayOfMonth, this);
         mDatePicker.setValidationCallback(mValidationCallback);
     }
 
+    /**
+     * Creates a new date picker dialog for the specified date using the parent
+     * context's default date picker dialog theme.
+     *
+     * @param context the parent context
+     * @param listener the listener to call when the user sets the date
+     * @param year the initially selected year
+     * @param month the initially selected month (0-11 for compatibility with
+     *              {@link Calendar#MONTH})
+     * @param dayOfMonth the initially selected day of month (1-31, depending
+     *                   on month)
+     */
+    public DatePickerDialog(@Nullable Context context, @Nullable OnDateSetListener listener,
+            int year, int month, int dayOfMonth) {
+        this(context, 0, listener, year, month, dayOfMonth);
+    }
+
+    /**
+     * Creates a new date picker dialog for the specified date.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
+     * @param listener the listener to call when the user sets the date
+     * @param year the initially selected year
+     * @param month the initially selected month (0-11 for compatibility with
+     *              {@link Calendar#MONTH})
+     * @param dayOfMonth the initially selected day of month (1-31, depending
+     *                   on month)
+     */
+    public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+            @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
+        this(context, themeResId);
+
+        mDateSetListener = listener;
+
+        mDatePicker.updateDate(year, month, dayOfMonth);
+    }
+
+    static int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
+        if (themeResId == 0) {
+            final TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
+            return outValue.resourceId;
+        } else {
+            return themeResId;
+        }
+    }
+
     @Override
-    public void onDateChanged(DatePicker view, int year, int month, int day) {
-        mDatePicker.init(year, month, day, this);
-        updateTitle(year, month, day);
+    public void onDateChanged(DatePicker view, int year, int month, int dayOfMonth) {
+        mDatePicker.init(year, month, dayOfMonth, this);
+        updateTitle(year, month, dayOfMonth);
+    }
+
+    /**
+     * Sets the listener to call when the user sets the date.
+     *
+     * @param listener the listener to call when the user sets the date
+     */
+    public void setOnDateSetListener(@Nullable OnDateSetListener listener) {
+        mDateSetListener = listener;
     }
 
     @Override
@@ -145,10 +179,11 @@
     }
 
     /**
-     * Gets the {@link DatePicker} contained in this dialog.
+     * Returns the {@link DatePicker} contained in this dialog.
      *
-     * @return The calendar view.
+     * @return the date picker
      */
+    @NonNull
     public DatePicker getDatePicker() {
         return mDatePicker;
     }
@@ -156,20 +191,22 @@
     /**
      * Sets the current date.
      *
-     * @param year The date year.
-     * @param monthOfYear The date month.
-     * @param dayOfMonth The date day of month.
+     * @param year the year
+     * @param month the month (0-11 for compatibility with
+     *              {@link Calendar#MONTH})
+     * @param dayOfMonth the day of month (1-31, depending on month)
      */
-    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
-        mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
+    public void updateDate(int year, int month, int dayOfMonth) {
+        mDatePicker.updateDate(year, month, dayOfMonth);
     }
 
-    private void updateTitle(int year, int month, int day) {
+    private void updateTitle(int year, int month, int dayOfMonth) {
         if (!mDatePicker.getCalendarViewShown()) {
             mCalendar.set(Calendar.YEAR, year);
             mCalendar.set(Calendar.MONTH, month);
-            mCalendar.set(Calendar.DAY_OF_MONTH, day);
-            String title = DateUtils.formatDateTime(mContext,
+            mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+
+            final String title = DateUtils.formatDateTime(mContext,
                     mCalendar.getTimeInMillis(),
                     DateUtils.FORMAT_SHOW_DATE
                     | DateUtils.FORMAT_SHOW_WEEKDAY
@@ -177,12 +214,12 @@
                     | DateUtils.FORMAT_ABBREV_MONTH
                     | DateUtils.FORMAT_ABBREV_WEEKDAY);
             setTitle(title);
+
             mTitleNeedsUpdate = true;
-        } else {
-            if (mTitleNeedsUpdate) {
-                mTitleNeedsUpdate = false;
-                setTitle(R.string.date_picker_dialog_title);
-            }
+        } else if (mTitleNeedsUpdate) {
+            setTitle(R.string.date_picker_dialog_title);
+
+            mTitleNeedsUpdate = false;
         }
     }
 
@@ -213,4 +250,19 @@
             }
         }
     };
+
+    /**
+     * The listener used to indicate the user has finished selecting a date.
+     */
+    public interface OnDateSetListener {
+        /**
+         * @param view the picker associated with the dialog
+         * @param year the selected year
+         * @param month the selected month (0-11 for compatibility with
+         *              {@link Calendar#MONTH})
+         * @param dayOfMonth th selected day of the month (1-31, depending on
+         *                   month)
+         */
+        void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
+    }
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index abe9822..e60cb03 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -78,6 +78,8 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
+    void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
     boolean isSystemConditionProviderEnabled(String path);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0f3ca10..c3dfab4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4169,11 +4169,18 @@
 
     /**
      * Internal flag used to indicate that a system component has done their
-     * homework and verified their encryption-aware behavior.
+     * homework and verified that they correctly handle packages and components
+     * that come and go over time. In particular:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
      *
      * @hide
      */
-    public static final int FLAG_DEBUG_ENCRYPTION_TRIAGED = 0x00000100;
+    public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
 
     /**
      * If set, the new activity is not kept in the history stack.  As soon as
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 69f508e..e0855de 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -93,6 +93,109 @@
     }
 
     /**
+     * As a guiding principle:
+     * <p>
+     * {@code GET_} flags are used to request additional data that may have been
+     * elided to save wire space.
+     * <p>
+     * {@code MATCH_} flags are used to include components or packages that
+     * would have otherwise been omitted from a result set by current system
+     * state.
+     */
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_ACTIVITIES,
+            GET_RECEIVERS,
+            GET_SERVICES,
+            GET_PROVIDERS,
+            GET_INSTRUMENTATION,
+            GET_INTENT_FILTERS,
+            GET_SIGNATURES,
+            GET_META_DATA,
+            GET_GIDS,
+            GET_SHARED_LIBRARY_FILES,
+            GET_URI_PERMISSION_PATTERNS,
+            GET_PERMISSIONS,
+            GET_CONFIGURATIONS,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PackageInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApplicationInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_ALL,
+            MATCH_DEFAULT_ONLY,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ComponentInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            GET_RESOLVED_FILTER,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_ALL,
+            MATCH_DEFAULT_ONLY,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResolveInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionGroupInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InstrumentationInfoFlags {}
+
+    /**
      * {@link PackageInfo} flag: return information about
      * activities in the package in {@link PackageInfo#activities}.
      */
@@ -161,9 +264,15 @@
     public static final int GET_GIDS                    = 0x00000100;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_COMPONENTS}
+     */
+    @Deprecated
+    public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+
+    /**
      * {@link PackageInfo} flag: include disabled components in the returned info.
      */
-    public static final int GET_DISABLED_COMPONENTS     = 0x00000200;
+    public static final int MATCH_DISABLED_COMPONENTS = 0x00000200;
 
     /**
      * {@link ApplicationInfo} flag: return the
@@ -190,6 +299,12 @@
     public static final int GET_PERMISSIONS               = 0x00001000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_UNINSTALLED_PACKAGES}
+     */
+    @Deprecated
+    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+
+    /**
      * Flag parameter to retrieve some information about all applications (even
      * uninstalled ones) which have data directories. This state could have
      * resulted if applications have been deleted with flag
@@ -199,7 +314,7 @@
      * Note: this flag may cause less information about currently installed
      * applications to be returned.
      */
-    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+    public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
 
     /**
      * {@link PackageInfo} flag: return information about
@@ -211,12 +326,18 @@
     public static final int GET_CONFIGURATIONS = 0x00004000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}.
+     */
+    @Deprecated
+    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+
+    /**
      * {@link PackageInfo} flag: include disabled components which are in
      * that state only because of {@link #COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED}
      * in the returned info.  Note that if you set this flag, applications
      * that are in this disabled state will be reported as enabled.
      */
-    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+    public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
 
     /**
      * Resolution and querying flag: if set, only filters that support the
@@ -227,48 +348,55 @@
     public static final int MATCH_DEFAULT_ONLY  = 0x00010000;
 
     /**
-     * Querying flag: if set and if the platform is doing any filtering of the results, then
-     * the filtering will not happen. This is a synonym for saying that all results should
-     * be returned.
+     * Querying flag: if set and if the platform is doing any filtering of the
+     * results, then the filtering will not happen. This is a synonym for saying
+     * that all results should be returned.
+     * <p>
+     * <em>This flag should be used with extreme care.</em>
      */
     public static final int MATCH_ALL = 0x00020000;
 
     /**
-     * {@link PackageInfo} flag: include only components which are encryption
-     * unaware in the returned info, regardless of the current user state.
+     * Querying flag: include only components which are encryption unaware in
+     * the returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 0x00040000;
+    public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
 
     /**
-     * {@link PackageInfo} flag: include only components which are encryption
-     * aware in the returned info, regardless of the current user state.
+     * Querying flag: include only components which are encryption aware in the
+     * returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_AWARE_ONLY = 0x00080000;
+    public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
 
     /**
-     * {@link PackageInfo} flag: include both encryption aware and unaware
-     * components in the returned info, regardless of the current user state.
+     * Querying flag: include both encryption aware and unaware components in
+     * the returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE_ONLY
-            | MATCH_ENCRYPTION_UNAWARE_ONLY;
+    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
+            | MATCH_ENCRYPTION_UNAWARE;
 
     /**
-     * {@link PackageInfo} flag: include only components from applications that
-     * are marked with {@link ApplicationInfo#FLAG_SYSTEM}.
-     *
-     * @hide
+     * Querying flag: include only components from applications that are marked
+     * with {@link ApplicationInfo#FLAG_SYSTEM}.
      */
     public static final int MATCH_SYSTEM_ONLY = 0x00100000;
 
     /**
-     * {@link PackageInfo} flag: use the default encryption matching behavior
-     * based on user state. Internal flag used to indicate that a system
-     * component has done their homework and verified their encryption-aware
-     * behavior.
+     * Internal flag used to indicate that a system component has done their
+     * homework and verified that they correctly handle packages and components
+     * that come and go over time. In particular:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
      *
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
      * @hide
      */
-    public static final int MATCH_ENCRYPTION_DEFAULT = 0x10000000;
+    public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
 
     /**
      * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
@@ -2131,7 +2259,7 @@
      * @see #GET_SIGNATURES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract PackageInfo getPackageInfo(String packageName, int flags)
+    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -2171,8 +2299,8 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-    public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
-            throws NameNotFoundException;
+    public abstract PackageInfo getPackageInfoAsUser(String packageName,
+            @PackageInfoFlags int flags, int userId) throws NameNotFoundException;
 
     /**
      * Map from the current package names in use on the device to whatever
@@ -2270,7 +2398,7 @@
      * @return Returns a {@link PermissionInfo} containing information about the
      *         permission.
      */
-    public abstract PermissionInfo getPermissionInfo(String name, int flags)
+    public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -2289,7 +2417,7 @@
      * about all of the permissions in the given group.
      */
     public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
-            int flags) throws NameNotFoundException;
+            @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular group of
@@ -2307,7 +2435,7 @@
      * about the permission.
      */
     public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
-            int flags) throws NameNotFoundException;
+            @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the known permission groups in the system.
@@ -2318,7 +2446,8 @@
      * @return Returns a list of {@link PermissionGroupInfo} containing
      * information about all of the known permission groups.
      */
-    public abstract List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+    public abstract List<PermissionGroupInfo> getAllPermissionGroups(
+            @PermissionGroupInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
@@ -2348,7 +2477,7 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName,
-            int flags) throws NameNotFoundException;
+            @ApplicationInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular activity
@@ -2371,7 +2500,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getActivityInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular receiver
@@ -2394,7 +2523,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getReceiverInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular service
@@ -2416,7 +2545,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ServiceInfo getServiceInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular content
@@ -2438,7 +2567,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ProviderInfo getProviderInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Return a List of all packages that are installed
@@ -2474,7 +2603,7 @@
      * @see #GET_SIGNATURES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags);
+    public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
 
     /**
      * Return a List of all installed packages that are currently
@@ -2507,7 +2636,7 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract List<PackageInfo> getPackagesHoldingPermissions(
-            String[] permissions, int flags);
+            String[] permissions, @PackageInfoFlags int flags);
 
     /**
      * Return a List of all packages that are installed on the device, for a specific user.
@@ -2546,7 +2675,7 @@
      *
      * @hide
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+    public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags, int userId);
 
     /**
      * Check whether a particular package has been granted a particular
@@ -2886,7 +3015,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+    public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
 
     /**
      * Gets the ephemeral applications the user recently used. Requires
@@ -3021,7 +3150,7 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract ResolveInfo resolveActivity(Intent intent, int flags);
+    public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Determine the best action to perform for a given Intent for a given user. This
@@ -3054,7 +3183,8 @@
      *
      * @hide
      */
-    public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+    public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
+            int userId);
 
     /**
      * Retrieve all activities that can be performed for the given intent.
@@ -3077,7 +3207,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all activities that can be performed for the given intent, for a specific user.
@@ -3101,8 +3231,7 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
-            int flags, int userId);
-
+            @ResolveInfoFlags int flags, int userId);
 
     /**
      * Retrieve a set of activities that should be presented to the user as
@@ -3134,7 +3263,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentActivityOptions(
-            ComponentName caller, Intent[] specifics, Intent intent, int flags);
+            ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent.
@@ -3151,7 +3280,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent, for a specific
@@ -3171,7 +3300,7 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags, int userId);
+            @ResolveInfoFlags int flags, int userId);
 
     /**
      * Determine the best service to handle for a given Intent.
@@ -3187,7 +3316,7 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract ResolveInfo resolveService(Intent intent, int flags);
+    public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent.
@@ -3205,7 +3334,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentServices(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent for a given user.
@@ -3226,11 +3355,11 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
-            int flags, int userId);
+            @ResolveInfoFlags int flags, int userId);
 
     /** {@hide} */
     public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
-            Intent intent, int flags, int userId);
+            Intent intent, @ResolveInfoFlags int flags, int userId);
 
     /**
      * Retrieve all providers that can match the given intent.
@@ -3244,7 +3373,8 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
+    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+            @ResolveInfoFlags int flags);
 
     /**
      * Find a single content provider by its base path name.
@@ -3256,7 +3386,7 @@
      *         else null.
      */
     public abstract ProviderInfo resolveContentProvider(String name,
-            int flags);
+            @ComponentInfoFlags int flags);
 
     /**
      * Find a single content provider by its base path name.
@@ -3269,7 +3399,8 @@
      *         else null.
      * @hide
      */
-    public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
+    public abstract ProviderInfo resolveContentProviderAsUser(String name,
+            @ComponentInfoFlags int flags, int userId);
 
     /**
      * Retrieve content provider information.
@@ -3290,7 +3421,7 @@
      *         <em>If there are no matching providers, null is returned.</em>
      */
     public abstract List<ProviderInfo> queryContentProviders(
-            String processName, int uid, int flags);
+            String processName, int uid, @ComponentInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
@@ -3307,8 +3438,8 @@
      * @return InstrumentationInfo containing information about the
      *         instrumentation.
      */
-    public abstract InstrumentationInfo getInstrumentationInfo(
-            ComponentName className, int flags) throws NameNotFoundException;
+    public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+            @InstrumentationInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve information about available instrumentation code.  May be used
@@ -3324,8 +3455,8 @@
      *         matching available Instrumentation.  Returns an empty list if
      *         there is no instrumentation available for the given package.
      */
-    public abstract List<InstrumentationInfo> queryInstrumentation(
-            String targetPackage, int flags);
+    public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+            @InstrumentationInfoFlags int flags);
 
     /**
      * Retrieve an image from a package.  This is a low-level API used by
@@ -3761,7 +3892,7 @@
      * @see #GET_SIGNATURES
      *
      */
-    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+    public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
         final PackageParser parser = new PackageParser();
         final File apkFile = new File(archiveFilePath);
         try {
@@ -4423,7 +4554,7 @@
      * @see #GET_SERVICES
      * @see #GET_SIGNATURES
      */
-    public abstract List<PackageInfo> getPreferredPackages(int flags);
+    public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
     /**
      * @deprecated This is a protected API that should not have been available
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index cfb4473..945858e6 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -50,6 +51,10 @@
 
     private final List<T> mList;
 
+    public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+        return new ParceledListSlice<T>(Collections.<T> emptyList());
+    }
+
     public ParceledListSlice(List<T> list) {
         mList = list;
     }
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 71d9d5d..4de36cd 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -120,6 +120,32 @@
         return mTrustManager;
     }
 
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application, which is the
+     * case only if all configurations permit cleartext traffic. For finer-grained policy use
+     * {@link #isCleartextTrafficPermitted(String)}.
+     */
+    public boolean isCleartextTrafficPermitted() {
+        ensureInitialized();
+        if (mConfigs != null) {
+            for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+                if (!entry.second.isCleartextTrafficPermitted()) {
+                    return false;
+                }
+            }
+        }
+
+        return mDefaultConfig.isCleartextTrafficPermitted();
+    }
+
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application when connecting
+     * to {@code hostname}.
+     */
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return getConfigForHostname(hostname).isCleartextTrafficPermitted();
+    }
+
     private void ensureInitialized() {
         synchronized(mLock) {
             if (mInitialized) {
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
new file mode 100644
index 0000000..e7d17c2
--- /dev/null
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.net.config;
+
+/**
+ * {@link libcore.net.NetworkSecurityPolicy} based on an {@link ApplicationConfig}.
+ *
+ * @hide
+ */
+public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+    private final ApplicationConfig mConfig;
+
+    public ConfigNetworkSecurityPolicy(ApplicationConfig config) {
+        mConfig = config;
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted() {
+        return mConfig.isCleartextTrafficPermitted();
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return mConfig.isCleartextTrafficPermitted(hostname);
+    }
+}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index 5ebc7ac..0f66873 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -40,5 +40,6 @@
             throw new RuntimeException("Failed to install provider as highest priority provider."
                     + " Provider was installed at position " + pos);
         }
+        libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
     }
 }
diff --git a/core/java/android/service/notification/INotificationAssistant.aidl b/core/java/android/service/notification/INotificationAssistant.aidl
deleted file mode 100644
index 5c5f358..0000000
--- a/core/java/android/service/notification/INotificationAssistant.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.notification;
-
-import android.service.notification.NotificationAdjustment;
-import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationRankingUpdate;
-
-/** @hide */
-interface INotificationAssistant
-{
-    void onListenerConnected(in NotificationRankingUpdate update);
-    void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
-            in NotificationRankingUpdate update);
-    void onNotificationRankingUpdate(in NotificationRankingUpdate update);
-    void onListenerHintsChanged(int hints);
-    void onInterruptionFilterChanged(int interruptionFilter);
-    NotificationAdjustment onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
-    void onNotificationVisibilityChanged(String key, long time, boolean visible);
-    void onNotificationClick(String key, long time);
-    void onNotificationActionClick(String key, long time, int actionIndex);
-    void onNotificationRemoved(String key, long time, int reason);
-}
\ No newline at end of file
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index e6bf6ba..a0de17f 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,6 +23,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
+    // listeners and assistants
     void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
@@ -31,4 +32,11 @@
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
+
+    // assistants only
+    void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+    void onNotificationVisibilityChanged(String key, long time, boolean visible);
+    void onNotificationClick(String key, long time);
+    void onNotificationActionClick(String key, long time, int actionIndex);
+    void onNotificationRemovedReason(String key, long time, int reason);
 }
diff --git a/core/java/android/service/notification/NotificationAdjustment.java b/core/java/android/service/notification/NotificationAdjustment.java
deleted file mode 100644
index c5f0db9..0000000
--- a/core/java/android/service/notification/NotificationAdjustment.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package android.service.notification;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class NotificationAdjustment implements Parcelable {
-    int mImportance;
-    CharSequence mExplanation;
-    Uri mReference;
-
-    /**
-     * Create a notification importance adjustment.
-     *
-     * @param importance The final importance of the notification.
-     * @param explanation A human-readable justification for the adjustment.
-     * @param reference A reference to an external object that augments the
-     *                  explanation, such as a
-     *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
-     *                  or null.
-     */
-    public NotificationAdjustment(int importance, CharSequence explanation, Uri reference) {
-        mImportance = importance;
-        mExplanation = explanation;
-        mReference = reference;
-    }
-
-    private NotificationAdjustment(Parcel source) {
-        this(source.readInt(), source.readCharSequence(),
-                (Uri) source.readParcelable(NotificationAdjustment.class.getClassLoader()));
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mImportance);
-        dest.writeCharSequence(mExplanation);
-        dest.writeParcelable(mReference, 0);
-    }
-
-    public static final Parcelable.Creator<NotificationAdjustment> CREATOR
-            = new Parcelable.Creator<NotificationAdjustment>() {
-        @Override
-        public NotificationAdjustment createFromParcel(Parcel source) {
-            return new NotificationAdjustment(source);
-        }
-
-        @Override
-        public NotificationAdjustment[] newArray(int size) {
-            return new NotificationAdjustment[size];
-        }
-    };
-}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 7ce5e1f..3a8956e 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -20,8 +20,11 @@
 import android.app.Notification;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
 
 /**
  * A service that helps the user manage notifications by modifying the
@@ -39,6 +42,8 @@
  * &lt;/service></pre>
  */
 public abstract class NotificationAssistantService extends NotificationListenerService {
+    private static final String TAG = "NotificationAssistant";
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
@@ -85,6 +90,36 @@
     /** Notification was canceled because it was an invisible member of a group. */
     public static final int REASON_GROUP_OPTIMIZATION = 13;
 
+    public class Adjustment {
+        int mImportance;
+        CharSequence mExplanation;
+        Uri mReference;
+
+        /**
+         * Create a notification importance adjustment.
+         *
+         * @param importance The final importance of the notification.
+         * @param explanation A human-readable justification for the adjustment.
+         * @param reference A reference to an external object that augments the
+         *                  explanation, such as a
+         *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
+         *                  or null.
+         */
+        public Adjustment(int importance, CharSequence explanation, Uri reference) {
+            mImportance = importance;
+            mExplanation = explanation;
+            mReference = reference;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new NotificationAssistantWrapper();
+        }
+        return mWrapper;
+    }
+
     /**
      * A notification was posted by an app. Called before alert.
      *
@@ -93,7 +128,7 @@
      * @param user true if the initial importance reflects an explicit user preference.
      * @return an adjustment or null to take no action, within 100ms.
      */
-    abstract public NotificationAdjustment onNotificationEnqueued(StatusBarNotification sbn,
+    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
           int importance, boolean user);
 
     /**
@@ -150,9 +185,15 @@
      * @param key the notification key
      * @param adjustment the new importance with an explanation
      */
-    public final void adjustImportance(String key, NotificationAdjustment adjustment)
+    public final void adjustImportance(String key, Adjustment adjustment)
     {
-        // TODO: pack up the adjustment and send it to the NotificationManager.
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
+                    adjustment.mImportance, adjustment.mExplanation);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
     }
 
     /**
@@ -160,7 +201,7 @@
      * be fired when the host notification is deleted, or when this annotation
      * is removed or replaced.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be annotated
      * @param annotation the new annotation object
      */
     public final void setAnnotation(String key, Notification annotation)
@@ -171,10 +212,74 @@
     /**
      * Remove the annotation from a notification.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be cleansed of annotatons
      */
     public final void clearAnnotation(String key)
     {
         // TODO: ask the NotificationManager to clear the annotation.
     }
+
+    private class NotificationAssistantWrapper extends NotificationListenerWrapper {
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+                                           int importance, boolean user) throws RemoteException {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+                return;
+            }
+
+            try {
+                Adjustment adjustment =
+                    NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
+                if (adjustment != null) {
+                    adjustImportance(sbn.getKey(), adjustment);
+                }
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationEnqueued", t);
+            }
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
+                        visible);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
+            }
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationClick(key, time);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationClick", t);
+            }
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationActionClick", t);
+            }
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationRemoved", t);
+            }
+        }
+    }
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1e62edc..6c99489 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,6 +15,7 @@
  */
 
 package android.service.notification;
+import android.service.notification.IStatusBarNotificationHolder;
 
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
@@ -151,7 +152,8 @@
     @SystemApi
     public static final int TRIM_LIGHT = 1;
 
-    private INotificationListenerWrapper mWrapper = null;
+    /** @hide */
+    protected NotificationListenerWrapper mWrapper = null;
     private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
@@ -291,7 +293,8 @@
         // optional
     }
 
-    private final INotificationManager getNotificationInterface() {
+    /** @hide */
+    protected final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -634,12 +637,13 @@
     @Override
     public IBinder onBind(Intent intent) {
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         return mWrapper;
     }
 
-    private boolean isBound() {
+    /** @hide */
+    protected boolean isBound() {
         if (mWrapper == null) {
             Log.w(TAG, "Notification listener service not yet bound.");
             return false;
@@ -664,7 +668,7 @@
             int currentUser) throws RemoteException {
         mSystemContext = context;
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         INotificationManager noMan = getNotificationInterface();
         noMan.registerListener(mWrapper, componentName, currentUser);
@@ -716,7 +720,8 @@
         }
     }
 
-    private class INotificationListenerWrapper extends INotificationListener.Stub {
+    /** @hide */
+    protected class NotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
@@ -817,6 +822,35 @@
                 Log.w(TAG, "Error running onInterruptionFilterChanged", t);
             }
         }
+
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
+                                           int importance, boolean user) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason)
+                throws RemoteException {
+            // no-op in the listener
+        }
     }
 
     private void applyUpdate(NotificationRankingUpdate update) {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index d8787b4..55fe4cd 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -26,17 +26,17 @@
 import android.view.WindowManager;
 
 /**
- * A QSTileService provides the user a tile that can be added to Quick Settings.
+ * A TileService provides the user a tile that can be added to Quick Settings.
  * Quick Settings is a space provided that allows the user to change settings and
  * take quick actions without leaving the context of their current app.
  *
- * <p>The lifecycle of a QSTileService is different from some other services in
+ * <p>The lifecycle of a TileService is different from some other services in
  * that it may be unbound during parts of its lifecycle.  Any of the following
  * lifecycle events can happen indepently in a separate binding/creation of the
  * service.</p>
  *
  * <ul>
- * <li>When a tile is added by the user its QSTileService will be bound to and
+ * <li>When a tile is added by the user its TileService will be bound to and
  * {@link #onTileAdded()} will be called.</li>
  *
  * <li>When a tile should be up to date and listing will be indicated by
@@ -45,10 +45,10 @@
  * <li>When the user removes a tile from Quick Settings {@link #onStopListening()}
  * will be called.</li>
  * </ul>
- * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
+ * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
  * and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE".
  * The label and icon for the service will be used as the default label and
- * icon for the tile. Here is an example QSTileService declaration.</p>
+ * icon for the tile. Here is an example TileService declaration.</p>
  * <pre class="prettyprint">
  * {@literal
  * <service
@@ -67,7 +67,7 @@
 public class TileService extends Service {
 
     /**
-     * Action that identifies a Service as being a QSTileService.
+     * Action that identifies a Service as being a TileService.
      */
     public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
 
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aa29636..914bd56 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -555,6 +555,26 @@
         }
     }
 
+    private static final ClassLoader BOOT_CLASS_LOADER = LayoutInflater.class.getClassLoader();
+
+    private final boolean verifyClassLoader(Constructor<? extends View> constructor) {
+        final ClassLoader constructorLoader = constructor.getDeclaringClass().getClassLoader();
+        if (constructorLoader == BOOT_CLASS_LOADER) {
+            // fast path for boot class loader (most common case?) - always ok
+            return true;
+        }
+        // in all normal cases (no dynamic code loading), we will exit the following loop on the
+        // first iteration (i.e. when the declaring classloader is the contexts class loader).
+        ClassLoader cl = mContext.getClassLoader();
+        do {
+            if (constructorLoader == cl) {
+                return true;
+            }
+            cl = cl.getParent();
+        } while (cl != null);
+        return false;
+    }
+
     /**
      * Low-level function for instantiating a view by name. This attempts to
      * instantiate a view class of the given <var>name</var> found in this
@@ -575,6 +595,10 @@
     public final View createView(String name, String prefix, AttributeSet attrs)
             throws ClassNotFoundException, InflateException {
         Constructor<? extends View> constructor = sConstructorMap.get(name);
+        if (constructor != null && !verifyClassLoader(constructor)) {
+            constructor = null;
+            sConstructorMap.remove(name);
+        }
         Class<? extends View> clazz = null;
 
         try {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 19e290b..7e98193 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1467,10 +1467,14 @@
         }
 
         if (mClipToScreen) {
+            final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
+            final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
+            p.x += winOffsetX;
+            p.y += winOffsetY;
             final int displayFrameWidth = displayFrame.right - displayFrame.left;
             final int right = p.x + p.width;
-            if (right > displayFrameWidth) {
-                p.x -= right - displayFrameWidth;
+            if (right > displayFrame.right) {
+                p.x -= right - displayFrame.right;
             }
 
             if (p.x < displayFrame.left) {
@@ -1479,10 +1483,9 @@
             }
 
             if (mOverlapAnchor) {
-                final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
                 final int bottom = p.y + p.height;
                 if (bottom > displayFrame.bottom) {
-                    p.y -= bottom - displayFrameHeight;
+                    p.y -= bottom - displayFrame.bottom;
                 }
             } else {
                 if (onTop) {
@@ -1494,6 +1497,8 @@
                     p.y = Math.max(p.y, displayFrame.top);
                 }
             }
+            p.x -= winOffsetX;
+            p.y -= winOffsetY;
         }
 
         p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index bfc56db..5fc7448 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -36,6 +36,7 @@
     public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
     public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
     public static final int QS_COLOR_MATRIX = 265;
+    public static final int QS_CUSTOM = 266;
 
     /**
      * Logged when the user docks a window from recents by longpressing a task and dragging it to
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1090f90..37af59f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -107,6 +107,7 @@
     <protected-broadcast android:name="android.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.backup.intent.INIT" />
 
+    <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -1901,7 +1902,7 @@
 
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
-         QSTileService declarations.-->
+         TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
         android:protectionLevel="signature" />
 
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
index 63d2c05..b1a58cd 100644
--- a/core/res/res/layout/text_drag_thumbnail.xml
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2010, The Android Open Source Project
 **
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 5177836..c0453f8 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -146,6 +146,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.DatePickerActivity"
+                android:label="DatePickerActivity"
+                android:screenOrientation="portrait"
+                android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/datepicker_layout.xml b/core/tests/coretests/res/layout/datepicker_layout.xml
new file mode 100644
index 0000000..a79f87d
--- /dev/null
+++ b/core/tests/coretests/res/layout/datepicker_layout.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <DatePicker
+            android:id="@+id/datePicker"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"/>
+    <EditText
+            android:id="@+id/belowPicker"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Some Text"
+            android:textAlignment="center"
+            android:layout_below="@id/datePicker"/>
+</RelativeLayout>
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
new file mode 100644
index 0000000..c3b25a1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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 android.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+/**
+ * A minimal application for DatePickerFocusTest.
+ */
+public class DatePickerActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.datepicker_layout);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
new file mode 100644
index 0000000..513e40f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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 android.widget;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * Test {@link DatePicker} focus changes.
+ */
+public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
+
+    private Activity mActivity;
+    private Instrumentation mInstrumentation;
+    private DatePicker mDatePicker;
+
+    public DatePickerFocusTest() {
+        super(DatePickerActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+
+        mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
+    }
+
+    /**
+     * Tabs (forward and backward) through the DatePicker to ensure the correct
+     * Views gain focus.
+     */
+    public void testFocusTravel() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(mDatePicker.requestFocus());
+            }
+        });
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(R.id.belowPicker);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+    }
+
+    private void sendKey(int keycode) {
+        mInstrumentation.sendKeyDownUpSync(keycode);
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void assertViewHasFocus(final int id) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View view = mActivity.findViewById(id);
+                assertTrue(view.hasFocus());
+            }
+        });
+    }
+
+    private void sendShiftKey(int keycode) {
+        final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftDown);
+
+        final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyDown);
+
+        final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyUp);
+
+        final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftUp);
+
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Tests to ensure the keyboard can select the current year.
+     */
+    public void testYearChoice() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.requestFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertEquals(yearSelect, mDatePicker.findFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertNotSame(View.VISIBLE, yearSelect.getVisibility());
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.hasFocus());
+                assertEquals(2014, mDatePicker.getYear());
+            }
+        });
+    }
+
+    public void testArrowThroughDays() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
+                prev.requestFocus();
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_TAB);
+        // Should select the current date and the date shouldn't change
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+        // Move right to January 24, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 24, 2016);
+        // Move down to January 31, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 31, 2016);
+        // Move up to January 5, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 5, 2016);
+        // Move up to prev arrow key
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        // tab back into the day-selection pager
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 5, 2016);
+
+        // Move up out again, then down back into the day-selection pager.
+        // It should land right below the prev button (1/3/2016)
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 3, 2016);
+
+        // Move left to previous month (12/12/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 12, 2015);
+        // Now make sure the start of the month works
+        // Move up to 12/5/2015 and right to 1/1/2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 1, 2016);
+        // Now make sure the left key goes back to previous month (12/5/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 5, 2015);
+        // Now go to a mismatched row (no such row on previous month)
+        // This moves over to 1/31/2016 and then left to 12/31/2015
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+    }
+
+    private void assertDateIs(int month, final int day, final int year) throws Throwable {
+        final int monthInt = month - 1; // months are 0-based
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(day, mDatePicker.getDayOfMonth());
+                assertEquals(year, mDatePicker.getYear());
+                assertEquals(monthInt, mDatePicker.getMonth());
+            }
+        });
+    }
+
+    private void setKnownDate() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index eb9b55f..c305f65 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -243,6 +243,7 @@
     dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
     dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
             (float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
+    dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
     dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
     dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
     dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0669596..083aeb7 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -53,6 +53,8 @@
 ProfileType Properties::sProfileType = ProfileType::None;
 bool Properties::sDisableProfileBars = false;
 
+bool Properties::waitForGpuCompletion = false;
+
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {'\0',};
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1dde7e0..88f1dbc 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -285,6 +285,9 @@
 
     static ProfileType getProfileType();
 
+    // Should be used only by test apps
+    static bool waitForGpuCompletion;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 78df297..466fef9d 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,8 +29,6 @@
 
 #define GLES_VERSION 2
 
-#define WAIT_FOR_GPU_COMPLETION 0
-
 // Android-specific addition that is used to show when frames began in systrace
 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
 
@@ -179,7 +177,10 @@
 }
 
 void EglManager::createContext() {
-    EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
+    EGLint attribs[] = {
+            EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
+            EGL_NONE
+    };
     mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
     LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
         "Failed to create context, error = %s", egl_error_str());
@@ -318,12 +319,10 @@
 
 bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
 
-#if WAIT_FOR_GPU_COMPLETION
-    {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
         ATRACE_NAME("Finishing GPU work");
         fence();
     }
-#endif
 
     EGLint rects[4];
     frame.map(screenDirty, rects);
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index df8d194..706f2ff 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -37,6 +37,7 @@
 public:
     struct Options {
         int count = 0;
+        int reportFrametimeWeight = 0;
     };
 
     template <class T>
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 8261220..a843e92 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -38,6 +38,30 @@
     }
 };
 
+template<class T>
+class ModifiedMovingAverage {
+public:
+    ModifiedMovingAverage(int weight) : mWeight(weight) {}
+
+    T add(T today) {
+        if (!mHasValue) {
+            mAverage = today;
+        } else {
+            mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
+        }
+        return mAverage;
+    }
+
+    T average() {
+        return mAverage;
+    }
+
+private:
+    bool mHasValue = false;
+    int mWeight;
+    T mAverage;
+};
+
 void run(const TestScene::Info& info, const TestScene::Options& opts) {
     // Switch to the real display
     gDisplay = getBuiltInDisplay();
@@ -67,22 +91,35 @@
     proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
 
     // Do a few cold runs then reset the stats so that the caches are all hot
-    for (int i = 0; i < 3; i++) {
+    for (int i = 0; i < 5; i++) {
         testContext.waitForVsync();
         nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
         UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
         proxy->syncAndDrawFrame();
     }
+
     proxy->resetProfileInfo();
+    proxy->fence();
+
+    ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
 
     for (int i = 0; i < opts.count; i++) {
         testContext.waitForVsync();
-
-        ATRACE_NAME("UI-Draw Frame");
         nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
-        UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
-        scene->doFrame(i);
-        proxy->syncAndDrawFrame();
+        {
+            ATRACE_NAME("UI-Draw Frame");
+            UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+            scene->doFrame(i);
+            proxy->syncAndDrawFrame();
+        }
+        proxy->fence();
+        nsecs_t done = systemTime(CLOCK_MONOTONIC);
+        if (opts.reportFrametimeWeight) {
+            avgMs.add((done - vsync) / 1000000.0);
+            if (i % 10 == 9) {
+                printf("Average frametime %.3fms\n", avgMs.average());
+            }
+        }
     }
 
     proxy->dumpProfileInfo(STDOUT_FILENO, 0);
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 619713c..1616a95 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,6 +17,7 @@
 #include "tests/common/TestScene.h"
 
 #include "protos/hwui.pb.h"
+#include "Properties.h"
 
 #include <getopt.h>
 #include <stdio.h>
@@ -25,26 +26,38 @@
 #include <unordered_map>
 #include <vector>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::test;
 
-static int gFrameCount = 150;
 static int gRepeatCount = 1;
 static std::vector<TestScene::Info> gRunTests;
+static TestScene::Options gOpts;
 
 void run(const TestScene::Info& info, const TestScene::Options& opts);
 
 static void printHelp() {
-    printf("\
-USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
-\n\
-OPTIONS:\n\
-  -c, --count=NUM      NUM loops a test should run (example, number of frames)\n\
-  -r, --runs=NUM       Repeat the test(s) NUM times\n\
-  -h, --help           Display this help\n\
-  --list               List all tests\n\
-\n");
+    printf(R"(
+USAGE: hwuitest [OPTIONS] <TESTNAME>
+
+OPTIONS:
+  -c, --count=NUM      NUM loops a test should run (example, number of frames)
+  -r, --runs=NUM       Repeat the test(s) NUM times
+  -h, --help           Display this help
+  --list               List all tests
+  --wait-for-gpu       Set this to wait for the GPU before producing the
+                       next frame. Note that without locked clocks this will
+                       pathologically bad performance due to large idle time
+  --report-frametime[=weight] If set, the test will print to stdout the
+                       moving average frametime. Weight is optional, default is 10
+  --cpuset=name        Adds the test to the specified cpuset before running
+                       Not supported on all devices and needs root
+)");
 }
 
 static void listTests() {
@@ -77,11 +90,56 @@
     }
 }
 
+static void moveToCpuSet(const char* cpusetName) {
+    if (access("/dev/cpuset/tasks", F_OK)) {
+        fprintf(stderr, "don't have access to cpusets, skipping...\n");
+        return;
+    }
+    static const int BUF_SIZE = 100;
+    char buffer[BUF_SIZE];
+
+    if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
+        fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
+        return;
+    }
+    int fd = open(buffer, O_WRONLY | O_CLOEXEC);
+    if (fd == -1) {
+        fprintf(stderr, "Error opening file %d\n", errno);
+        return;
+    }
+    pid_t pid = getpid();
+
+    int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+    if (towrite >= BUF_SIZE) {
+        fprintf(stderr, "Buffer wasn't large enough?\n");
+    } else {
+        if (write(fd, buffer, towrite) != towrite) {
+            fprintf(stderr, "Failed to write, errno=%d", errno);
+        }
+    }
+    close(fd);
+}
+
+// For options that only exist in long-form. Anything in the
+// 0-255 range is reserved for short options (which just use their ASCII value)
+namespace LongOpts {
+enum {
+    Reserved = 255,
+    List,
+    WaitForGpu,
+    ReportFrametime,
+    CpuSet,
+};
+}
+
 static const struct option LONG_OPTIONS[] = {
     { "frames", required_argument, nullptr, 'f' },
     { "repeat", required_argument, nullptr, 'r' },
     { "help", no_argument, nullptr, 'h' },
-    { "list", no_argument, nullptr, 'l' },
+    { "list", no_argument, nullptr, LongOpts::List },
+    { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
+    { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
+    { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
     { 0, 0, 0, 0 }
 };
 
@@ -89,8 +147,6 @@
 
 void parseOptions(int argc, char* argv[]) {
     int c;
-    // temporary variable
-    int count;
     bool error = false;
     opterr = 0;
 
@@ -110,31 +166,53 @@
             // (although none of the current LONG_OPTIONS do this...)
             break;
 
-        case 'l':
+        case LongOpts::List:
             listTests();
             exit(EXIT_SUCCESS);
             break;
 
         case 'c':
-            count = atoi(optarg);
-            if (!count) {
+            gOpts.count = atoi(optarg);
+            if (!gOpts.count) {
                 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
                 error = true;
-            } else {
-                gFrameCount = (count > 0 ? count : INT_MAX);
             }
             break;
 
         case 'r':
-            count = atoi(optarg);
-            if (!count) {
+            gRepeatCount = atoi(optarg);
+            if (!gRepeatCount) {
                 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
                 error = true;
             } else {
-                gRepeatCount = (count > 0 ? count : INT_MAX);
+                gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
             }
             break;
 
+        case LongOpts::ReportFrametime:
+            if (optarg) {
+                gOpts.reportFrametimeWeight = atoi(optarg);
+                if (!gOpts.reportFrametimeWeight) {
+                    fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+                    error = true;
+                }
+            } else {
+                gOpts.reportFrametimeWeight = 10;
+            }
+            break;
+
+        case LongOpts::WaitForGpu:
+            Properties::waitForGpuCompletion = true;
+            break;
+
+        case LongOpts::CpuSet:
+            if (!optarg) {
+                error = true;
+                break;
+            }
+            moveToCpuSet(optarg);
+            break;
+
         case 'h':
             printHelp();
             exit(EXIT_SUCCESS);
@@ -172,13 +250,14 @@
 }
 
 int main(int argc, char* argv[]) {
+    // set defaults
+    gOpts.count = 150;
+
     parseOptions(argc, argv);
 
-    TestScene::Options opts;
-    opts.count = gFrameCount;
     for (int i = 0; i < gRepeatCount; i++) {
         for (auto&& test : gRunTests) {
-            run(test, opts);
+            run(test, gOpts);
         }
     }
     printf("Success!\n");
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
new file mode 100755
index 0000000..09d4869
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+adb root
+adb wait-for-device
+adb shell stop mpdecision
+adb shell stop perfd
+adb shell stop
+for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
+    adb shell kill $pid
+done
+adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell daemonize surfaceflinger
+sleep 3
+adb shell setprop service.bootanim.exit 1
+
+# cpu possible frequencies
+# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
+# 484500 510000 535500 561000 586500 612000 637500 663000 688500 714000 739500
+# 765000 790500 816000 841500 867000 892500 918000 943500 969000 994500 1020000
+# 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1938000
+# 2014500 2091000 2193000 2295000 2397000 2499000
+
+S=1326000
+echo "set cpu $cpu to $S hz";
+adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+
+#disable hotplug
+adb shell "echo 0 > /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable"
+
+# gbus possible rates
+# 72000 108000 180000 252000 324000 396000 468000 540000 612000 648000
+# 684000 708000 756000 804000 852000 (kHz)
+
+S=324000000
+echo "set gpu to $s hz"
+adb shell "echo 1 > /d/clock/override.gbus/state"
+adb shell "echo $S > /d/clock/override.gbus/rate"
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 82fd512..3dc5d7e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -158,11 +158,14 @@
             builder.addAction(secondAction);
         }
 
-        if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+        if (printJob.getState() == PrintJobInfo.STATE_STARTED
+                || printJob.getState() == PrintJobInfo.STATE_QUEUED) {
             float progress = printJob.getProgress();
             if (progress >= 0) {
-                builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+                builder.setProgress(Integer.MAX_VALUE, (int) (Integer.MAX_VALUE * progress),
                         false);
+            } else {
+                builder.setProgress(Integer.MAX_VALUE, 0, true);
             }
         }
 
diff --git a/packages/SystemUI/res/layout/assist_orb.xml b/packages/SystemUI/res/layout/assist_orb.xml
index ab0a0a5b..0036ed6 100644
--- a/packages/SystemUI/res/layout/assist_orb.xml
+++ b/packages/SystemUI/res/layout/assist_orb.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2012, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6ae5cf3..a20ec8e 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index d58664f..8498a4f 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 3cdee64..071b7c8 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -29,25 +29,22 @@
         android:background="@color/notification_guts_text_color" >
 
     <!-- header -->
-    <FrameLayout
+    <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingBottom="8dp" >
+            android:paddingBottom="8dp"
+            android:paddingTop="8dp"
+            android:id="@+id/notification_guts_header"
+            android:orientation="horizontal"
+            android:layout_gravity="center_vertical|start">
 
-        <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:id="@+id/notification_guts_header"
-                android:orientation="horizontal"
-                android:layout_gravity="center_vertical|start"
-                android:layout_marginEnd="52dp">
-                    <ImageView
-                            android:id="@android:id/icon"
-                            android:layout_width="18dp"
-                            android:layout_height="18dp"
-                            android:layout_marginEnd="3dp"
-                            android:src="@android:drawable/arrow_down_float" />
-                    <TextView
+        <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="18dp"
+                android:layout_height="18dp"
+                android:layout_marginEnd="3dp"
+                android:src="@android:drawable/arrow_down_float" />
+        <TextView
                             android:id="@+id/pkgname"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
@@ -55,7 +52,7 @@
                             android:layout_marginStart="3dp"
                             android:layout_marginEnd="4dp"
                             android:textColor="@color/notification_guts_title_color" />
-                    <TextView
+        <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:id="@+id/debug_info"
@@ -64,18 +61,7 @@
                             android:layout_gravity="bottom|start"
                             android:visibility="gone"
                             android:textColor="#ffffff" />
-        </LinearLayout>
-
-        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-                android:id="@+id/notification_inspect_item"
-                android:layout_width="52dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:gravity="center"
-                android:layout_gravity="center_vertical|end"
-                android:contentDescription="@string/status_bar_notification_inspect_item_title"
-                android:src="@drawable/ic_settings" />
-    </FrameLayout>
+    </LinearLayout>
     <!-- Importance slider -->
     <LinearLayout
             android:layout_width="match_parent"
@@ -157,4 +143,34 @@
                          android:visibility="gone"/>
         </RadioGroup>
     </LinearLayout>
+    <!-- buttons -->
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:paddingTop="8dp"
+            android:paddingBottom="16dp" >
+
+        <TextView
+            android:id="@+id/more_settings"
+            android:text="@string/notification_more_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.NotificationGuts"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:paddingEnd="24dp"
+            android:paddingStart="12dp"
+            android:focusable="true" />
+
+        <TextView
+            android:id="@+id/done"
+            android:text="@string/notification_done"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.NotificationGuts"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:focusable="true"/>
+    </LinearLayout>
 </com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 2b82b05..5b44c17 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -34,9 +34,10 @@
             android:layout_gravity="bottom|right"
             android:layout_marginRight="15dp"
             android:layout_marginBottom="15dp"
-            android:translationZ="2dp"
+            android:translationZ="4dp"
             android:contentDescription="@string/recents_lock_to_app_button_label"
-            android:background="@drawable/recents_lock_to_task_button_bg">
+            android:background="@drawable/recents_lock_to_task_button_bg"
+            android:visibility="invisible">
             <ImageView
                 android:layout_width="@dimen/recents_lock_to_app_icon_size"
                 android:layout_height="@dimen/recents_lock_to_app_icon_size"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index f8bd6fd..198e658 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index a5b3a83..aaa5a09 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2006, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bfa13e2..12cf137 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2006, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
index 1675773..adfaed13 100644
--- a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 45ddd50..876c21e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1228,6 +1228,11 @@
     <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
     <string name="notification_importance_max">Peek onto the screen and make sound</string>
 
+    <!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
+    <string name="notification_more_settings">More settings</string>
+    <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
+    <string name="notification_done">Done</string>
+
     <!-- Label for no color transform [CHAR LIMIT=30] -->
     <string name="color_matrix_none">Normal colors</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3b0ab791..527b638 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -317,4 +317,12 @@
         <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
     </style>
 
+    <style name="TextAppearance.NotificationGuts">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">@color/notification_guts_btn_color</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:gravity">center</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index b56ad76..01eb5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -75,7 +75,8 @@
             iv.setTag(R.id.qs_icon_tag, state.icon);
             if (d instanceof Animatable) {
                 Animatable a = (Animatable) d;
-                if (state.icon instanceof QSTile.AnimationIcon && !iv.isShown()) {
+                a.start();
+                if (!iv.isShown()) {
                     a.stop(); // skip directly to end state
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39f0c55..1a36abd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,8 +19,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
@@ -29,9 +27,20 @@
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
-
 import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.*;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.util.Collection;
 import java.util.Objects;
@@ -389,11 +398,7 @@
 
         @Override
         public Drawable getDrawable(Context context) {
-            Drawable d = context.getDrawable(mResId);
-            if (d instanceof Animatable) {
-                ((Animatable) d).start();
-            }
-            return d;
+            return context.getDrawable(mResId);
         }
 
         @Override
@@ -408,41 +413,14 @@
     }
 
     protected class AnimationIcon extends ResourceIcon {
-        private boolean mAllowAnimation;
-
         public AnimationIcon(int resId) {
             super(resId);
         }
 
-        public void setAllowAnimation(boolean allowAnimation) {
-            mAllowAnimation = allowAnimation;
-        }
-
         @Override
         public Drawable getDrawable(Context context) {
             // workaround: get a clean state for every new AVD
-            final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
-                    .getConstantState().newDrawable();
-            d.start();
-            if (mAllowAnimation) {
-                mAllowAnimation = false;
-            } else {
-                d.stop(); // skip directly to end state
-            }
-            return d;
-        }
-    }
-
-    protected enum UserBoolean {
-        USER_TRUE(true, true),
-        USER_FALSE(true, false),
-        BACKGROUND_TRUE(false, true),
-        BACKGROUND_FALSE(false, false);
-        public final boolean value;
-        public final boolean userInitiated;
-        private UserBoolean(boolean userInitiated, boolean value) {
-            this.value = value;
-            this.userInitiated = userInitiated;
+            return context.getDrawable(mResId).getConstantState().newDrawable();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
deleted file mode 100644
index a5e1fd5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.android.systemui.qs;
-
-import android.os.IBinder;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-
-
-public class QSTileServiceWrapper implements IQSTileService {
-    private static final String TAG = "IQSTileServiceWrapper";
-
-    private final IQSTileService mService;
-    
-    public QSTileServiceWrapper(IQSTileService service) {
-        mService = service;
-    }
-
-    @Override
-    public IBinder asBinder() {
-        return mService.asBinder();
-    }
-
-    @Override
-    public void setQSTile(Tile tile) {
-        try {
-            mService.setQSTile(tile);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileAdded() {
-        try {
-            mService.onTileAdded();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileRemoved() {
-        try {
-            mService.onTileRemoved();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStartListening() {
-        try {
-            mService.onStartListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStopListening() {
-        try {
-            mService.onStopListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onClick(IBinder token) {
-        try {
-            mService.onClick(token);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 87c29735..5ac63bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -35,8 +35,8 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.QSTileServiceWrapper;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.TunerService;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 6706c7a..a6a7143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,7 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.Icon;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.QSPagingSwitch;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
similarity index 71%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
rename to packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index bb74f34..e622e11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -11,23 +11,17 @@
  * 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.
+ * limitations under the License
  */
+package com.android.systemui.qs.external;
 
-package com.android.systemui.qs.tiles;
-
-import android.app.ActivityManager;
-import android.app.Service;
 import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.util.Log;
@@ -36,7 +30,6 @@
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class CustomTile extends QSTile<QSTile.State> {
@@ -52,8 +45,9 @@
     private final Tile mTile;
     private final IWindowManager mWindowManager;
     private final IBinder mToken = new Binder();
+    private final IQSTileService mService;
+    private final TileServiceManager mServiceManager;
 
-    private QSTileServiceWrapper mService;
     private boolean mListening;
     private boolean mBound;
     private boolean mIsTokenGranted;
@@ -63,7 +57,9 @@
         super(host);
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         mComponent = ComponentName.unflattenFromString(action);
-        mTile = new Tile(mComponent, host);
+        mServiceManager = host.getTileServices().getTileWrapper(this);
+        mService = mServiceManager.getTileService();
+        mTile = new Tile(mComponent, host.getTileServices());
         try {
             PackageManager pm = mContext.getPackageManager();
             ServiceInfo info = pm.getServiceInfo(mComponent, 0);
@@ -96,42 +92,32 @@
     public void setListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
-        if (listening) {
-            mHandler.removeCallbacks(mUnbind);
-            if (!mBound) {
-                // TODO: Guarantee re-bind on user-switch.
-                mContext.bindServiceAsUser(new Intent().setComponent(mComponent),
-                        mServiceConnection, Service.BIND_AUTO_CREATE,
-                        new UserHandle(ActivityManager.getCurrentUser()));
-                mBound = true;
+        try {
+            if (listening) {
+                mServiceManager.setBindRequested(true);
+                mService.setQSTile(mTile);
+                mService.onStartListening();
             } else {
-                if (mService != null) {
-                    mService.onStartListening();
-                } else {
-                    Log.d(TAG, "Can't start service listening");
-                }
-            }
-        } else {
-            if (mService != null) {
                 mService.onStopListening();
-            }
-            if (mIsTokenGranted && !mIsShowingDialog) {
-                try {
-                    if (DEBUG) Log.d(TAG, "Removing token");
-                    mWindowManager.removeWindowToken(mToken);
-                } catch (RemoteException e) {
+                if (mIsTokenGranted && !mIsShowingDialog) {
+                    try {
+                        if (DEBUG) Log.d(TAG, "Removing token");
+                        mWindowManager.removeWindowToken(mToken);
+                    } catch (RemoteException e) {
+                    }
+                    mIsTokenGranted = false;
                 }
-                mIsTokenGranted = false;
+                mIsShowingDialog = false;
+                mServiceManager.setBindRequested(false);
             }
-            mIsShowingDialog = false;
-            mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
         }
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mHandler.removeCallbacks(mUnbind);
         if (mIsTokenGranted) {
             try {
                 if (DEBUG) Log.d(TAG, "Removing token");
@@ -139,7 +125,6 @@
             } catch (RemoteException e) {
             }
         }
-        mUnbind.run();
     }
 
     @Override
@@ -161,7 +146,11 @@
                 mIsTokenGranted = true;
             } catch (RemoteException e) {
             }
-            mService.onClick(mToken);
+            try {
+                mService.onClick(mToken);
+            } catch (RemoteException e) {
+                // Called through wrapper, won't happen here.
+            }
         } else {
             Log.e(TAG, "Click with no service " + getTileSpec());
         }
@@ -187,34 +176,9 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_INTENT;
+        return MetricsLogger.QS_CUSTOM;
     }
 
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mService = new QSTileServiceWrapper(IQSTileService.Stub.asInterface(service));
-            if (mListening) {
-                mService.setQSTile(mTile);
-                mService.onStartListening();
-            } else {
-                mService.onStopListening();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    };
-
-    private final Runnable mUnbind = new Runnable() {
-        @Override
-        public void run() {
-            mContext.unbindService(mServiceConnection);
-            mBound = false;
-        }
-    };
-
     public static ComponentName getComponentFromSpec(String spec) {
         final String action = spec.substring(PREFIX.length(), spec.length() - 1);
         if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
new file mode 100644
index 0000000..d656686
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.os.IBinder;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.util.Log;
+
+
+public class QSTileServiceWrapper {
+    private static final String TAG = "IQSTileServiceWrapper";
+
+    private final IQSTileService mService;
+
+    public QSTileServiceWrapper(IQSTileService service) {
+        mService = service;
+    }
+
+    public IBinder asBinder() {
+        return mService.asBinder();
+    }
+
+    public boolean setQSTile(Tile tile) {
+        try {
+            mService.setQSTile(tile);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileAdded() {
+        try {
+            mService.onTileAdded();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileRemoved() {
+        try {
+            mService.onTileRemoved();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStartListening() {
+        try {
+            mService.onStartListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStopListening() {
+        try {
+            mService.onStopListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onClick(IBinder token) {
+        try {
+            mService.onClick(token);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
new file mode 100644
index 0000000..500ee19
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.Log;
+import libcore.util.Objects;
+
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of a TileService.
+ * <p>
+ * Will keep track of all calls on the IQSTileService interface and will relay those calls to the
+ * TileService as soon as it is bound.  It will only bind to the service when it is allowed to
+ * ({@link #setBindService(boolean)}) and when the service is available.
+ */
+public class TileLifecycleManager extends BroadcastReceiver implements
+        IQSTileService, ServiceConnection, IBinder.DeathRecipient {
+    public static final boolean DEBUG = false;
+
+    private static final String TAG = "TileLifecycleManager";
+
+    private static final int MSG_ON_ADDED = 0;
+    private static final int MSG_ON_REMOVED = 1;
+    private static final int MSG_ON_CLICK = 2;
+
+    // Bind retry control.
+    private static final int MAX_BIND_RETRIES = 5;
+    private static final int BIND_RETRY_DELAY = 1000;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Intent mIntent;
+    private final UserHandle mUser;
+
+    private Set<Integer> mQueuedMessages = new ArraySet<>();
+    private QSTileServiceWrapper mWrapper;
+    private boolean mListening;
+    private Tile mTile;
+    private IBinder mClickBinder;
+
+    private int mBindTryCount;
+    private boolean mBound;
+    @VisibleForTesting
+    boolean mReceiverRegistered;
+
+    public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+        mContext = context;
+        mHandler = handler;
+        mIntent = intent;
+        mUser = user;
+    }
+
+    public boolean hasPendingClick() {
+        synchronized (mQueuedMessages) {
+            return mQueuedMessages.contains(MSG_ON_CLICK);
+        }
+    }
+
+    public void setBindService(boolean bind) {
+        mBound = bind;
+        if (bind) {
+            if (mBindTryCount == MAX_BIND_RETRIES) {
+                // Too many failures, give up on this tile until an update.
+                startPackageListening();
+                return;
+            }
+            if (!checkComponentState()) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+            mBindTryCount++;
+            mContext.bindServiceAsUser(mIntent, this,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                    mUser);
+        } else {
+            if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent);
+            // Give it another chance next time it needs to be bound, out of kindness.
+            mBindTryCount = 0;
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+        // Got a connection, set the binding count to 0.
+        mBindTryCount = 0;
+        mWrapper = new QSTileServiceWrapper(Stub.asInterface(service));
+        try {
+            service.linkToDeath(this, 0);
+        } catch (RemoteException e) {
+        }
+        handlePendingMessages();
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+        mWrapper = null;
+    }
+
+    private void handlePendingMessages() {
+        // This ordering is laid out manually to make sure we preserve the TileService
+        // lifecycle.
+        ArraySet<Integer> queue;
+        synchronized (mQueuedMessages) {
+            queue = new ArraySet<>(mQueuedMessages);
+            mQueuedMessages.clear();
+        }
+        if (queue.contains(MSG_ON_ADDED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+            onTileAdded();
+        }
+        if (mListening) {
+            if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+            setQSTile(mTile);
+            onStartListening();
+        }
+        if (queue.contains(MSG_ON_CLICK)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onClick");
+            if (!mListening) {
+                Log.w(TAG, "Managed to get click on non-listening state...");
+                // Skipping click since lost click privileges.
+            } else {
+                onClick(mClickBinder);
+            }
+        }
+        if (queue.contains(MSG_ON_REMOVED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+            if (mListening) {
+                Log.w(TAG, "Managed to get remove in listening state...");
+                onStopListening();
+            }
+            onTileRemoved();
+        }
+    }
+
+    public void handleDestroy() {
+        if (DEBUG) Log.d(TAG, "handleDestroy");
+        if (mReceiverRegistered) {
+            stopPackageListening();
+        }
+    }
+
+    private void handleDeath() {
+        if (mWrapper == null) return;
+        mWrapper = null;
+        if (!mBound) return;
+        if (DEBUG) Log.d(TAG, "handleDeath");
+        if (checkComponentState()) {
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    if (mBound) {
+                        // Retry binding.
+                        setBindService(true);
+                    }
+                }
+            }, BIND_RETRY_DELAY);
+        }
+    }
+
+    @Override
+    public void setQSTile(Tile tile) {
+        if (DEBUG) Log.d(TAG, "setQSTile " + tile);
+        mTile = tile;
+        if (mWrapper != null && !mWrapper.setQSTile(tile)) {
+            handleDeath();
+        }
+    }
+
+    private boolean checkComponentState() {
+        PackageManager pm = mContext.getPackageManager();
+        if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+            startPackageListening();
+            return false;
+        }
+        return true;
+    }
+
+    private void startPackageListening() {
+        if (DEBUG) Log.d(TAG, "startPackageListening");
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+        mReceiverRegistered = true;
+    }
+
+    private void stopPackageListening() {
+        if (DEBUG) Log.d(TAG, "stopPackageListening");
+        mContext.unregisterReceiver(this);
+        mReceiverRegistered = false;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (DEBUG) Log.d(TAG, "onReceive: " + intent);
+        Uri data = intent.getData();
+        String pkgName = data.getEncodedSchemeSpecificPart();
+        if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
+            return;
+        }
+        stopPackageListening();
+        if (mBound) {
+            // Trying to bind again will check the state of the package before bothering to bind.
+            if (DEBUG) Log.d(TAG, "Trying to rebind");
+            setBindService(true);
+        }
+    }
+
+    private boolean isComponentAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+                    0, mUser.getIdentifier());
+            if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+            return si != null;
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+        return false;
+    }
+
+    private boolean isPackageAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
+            else Log.d(TAG, "Package not available: " + packageName);
+        }
+        return false;
+    }
+
+    private void queueMessage(int message) {
+        synchronized (mQueuedMessages) {
+            mQueuedMessages.add(message);
+        }
+    }
+
+    @Override
+    public void onTileAdded() {
+        if (DEBUG) Log.d(TAG, "onTileAdded");
+        if (mWrapper == null || !mWrapper.onTileAdded()) {
+            queueMessage(MSG_ON_ADDED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onTileRemoved() {
+        if (DEBUG) Log.d(TAG, "onTileRemoved");
+        if (mWrapper == null || !mWrapper.onTileRemoved()) {
+            queueMessage(MSG_ON_REMOVED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStartListening() {
+        if (DEBUG) Log.d(TAG, "onStartListening");
+        mListening = true;
+        if (mWrapper != null && !mWrapper.onStartListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStopListening() {
+        if (DEBUG) Log.d(TAG, "onStopListening");
+        mListening = false;
+        if (mWrapper != null && !mWrapper.onStopListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onClick(IBinder iBinder) {
+        if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+        if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+            mClickBinder = iBinder;
+            queueMessage(MSG_ON_CLICK);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public IBinder asBinder() {
+        return mWrapper != null ? mWrapper.asBinder() : null;
+    }
+
+    @Override
+    public void binderDied() {
+        if (DEBUG) Log.d(TAG, "binderDeath");
+        handleDeath();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
new file mode 100644
index 0000000..ca589df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+/**
+ * Manages the priority which lets {@link TileServices} make decisions about which tiles
+ * to bind.  Also holds on to and manages the {@link TileLifecycleManager}, informing it
+ * of when it is allowed to bind based on decisions frome the {@link TileServices}.
+ */
+public class TileServiceManager {
+
+    private static final long MIN_BIND_TIME = 5000;
+    private static final long UNBIND_DELAY = 30000;
+
+    public static final boolean DEBUG = true;
+
+    private static final String TAG = "TileServiceManager";
+
+    private final TileServices mServices;
+    private final TileLifecycleManager mStateManager;
+    private final Handler mHandler;
+    private boolean mBindRequested;
+    private boolean mBindAllowed;
+    private boolean mBound;
+    private int mPriority;
+    private boolean mJustBound;
+    private long mLastUpdate;
+
+    TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+        this(tileServices, handler, new TileLifecycleManager(handler,
+                tileServices.getContext(), new Intent().setComponent(component),
+                new UserHandle(ActivityManager.getCurrentUser())));
+    }
+
+    @VisibleForTesting
+    TileServiceManager(TileServices tileServices, Handler handler,
+            TileLifecycleManager tileLifecycleManager) {
+        mServices = tileServices;
+        mHandler = handler;
+        mStateManager = tileLifecycleManager;
+    }
+
+    public IQSTileService getTileService() {
+        return mStateManager;
+    }
+
+    public void setBindRequested(boolean bindRequested) {
+        if (mBindRequested == bindRequested) return;
+        mBindRequested = bindRequested;
+        if (mBindAllowed && mBindRequested && !mBound) {
+            bindService();
+        } else {
+            mServices.recalculateBindAllowance();
+        }
+        if (mBound && !mBindRequested) {
+            // TODO: Schedule unbind.
+        }
+    }
+
+    public void setLastUpdate(long lastUpdate) {
+        mLastUpdate = lastUpdate;
+        mServices.recalculateBindAllowance();
+    }
+
+    public void handleDestroy() {
+        mStateManager.handleDestroy();
+    }
+
+    public void setBindAllowed(boolean allowed) {
+        if (mBindAllowed == allowed) return;
+        mBindAllowed = allowed;
+        if (!mBindAllowed && mBound) {
+            unbindService();
+        } else if (mBindAllowed && mBindRequested && !mBound) {
+            bindService();
+        }
+    }
+
+    private void bindService() {
+        if (mBound) {
+            Log.e(TAG, "Service already bound");
+            return;
+        }
+        mBound = true;
+        mJustBound = true;
+        mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        if (!mBound) {
+            Log.e(TAG, "Service not bound");
+            return;
+        }
+        mBound = false;
+        mJustBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    public void calculateBindPriority(long currentTime) {
+        if (mStateManager.hasPendingClick()) {
+            // Pending click is the most important thing, need to put this service at the top of
+            // the list to be bound.
+            mPriority = Integer.MAX_VALUE;
+        } else if (mJustBound) {
+            // If we just bound, lets not thrash on binding/unbinding too much, this is second most
+            // important.
+            mPriority = Integer.MAX_VALUE - 1;
+        } else if (!mBindRequested) {
+            // Don't care about binding right now, put us last.
+            mPriority = Integer.MIN_VALUE;
+        } else {
+            // Order based on whether this was just updated.
+            long timeSinceUpdate = currentTime - mLastUpdate;
+            // Fit compare into integer space for simplicity. Make sure to leave MAX_VALUE and
+            // MAX_VALUE - 1 for the more important states above.
+            if (timeSinceUpdate > Integer.MAX_VALUE - 2) {
+                mPriority = Integer.MAX_VALUE - 2;
+            } else {
+                mPriority = (int) timeSinceUpdate;
+            }
+        }
+    }
+
+    public int getBindPriority() {
+        return mPriority;
+    }
+
+    @VisibleForTesting
+    final Runnable mJustBoundOver = new Runnable() {
+        @Override
+        public void run() {
+            mJustBound = false;
+            mServices.recalculateBindAllowance();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
new file mode 100644
index 0000000..d110d97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.Tile;
+import android.util.ArrayMap;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Runs the day-to-day operations of which tiles should be bound and when.
+ */
+public class TileServices extends IQSService.Stub {
+    static final int DEFAULT_MAX_BOUND = 3;
+    static final int REDUCED_MAX_BOUND = 1;
+
+    private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
+    private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+    private final Context mContext;
+    private final Handler mHandler;
+    private final QSTileHost mHost;
+
+    private int mMaxBound = DEFAULT_MAX_BOUND;
+
+    public TileServices(QSTileHost host, Looper looper) {
+        mHost = host;
+        mContext = mHost.getContext();
+        mHandler = new Handler(looper);
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public TileServiceManager getTileWrapper(CustomTile tile) {
+        ComponentName component = tile.getComponent();
+        TileServiceManager service = onCreateTileService(component);
+        synchronized (mServices) {
+            mServices.put(tile, service);
+            mTiles.put(component, tile);
+        }
+        return service;
+    }
+
+    protected TileServiceManager onCreateTileService(ComponentName component) {
+        return new TileServiceManager(this, mHandler, component);
+    }
+
+    public void freeService(CustomTile tile, TileServiceManager service) {
+        synchronized (mServices) {
+            service.setBindAllowed(false);
+            mServices.remove(tile);
+            mTiles.remove(tile.getComponent());
+        }
+    }
+
+    public void setMemoryPressure(boolean memoryPressure) {
+        mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
+        recalculateBindAllowance();
+    }
+
+    public void recalculateBindAllowance() {
+        final ArrayList<TileServiceManager> services;
+        synchronized (mServices) {
+            services = new ArrayList<>(mServices.values());
+        }
+        final int N = services.size();
+        if (N > mMaxBound) {
+            long currentTime = System.currentTimeMillis();
+            // Precalculate the priority of services for binding.
+            for (int i = 0; i < N; i++) {
+                services.get(i).calculateBindPriority(currentTime);
+            }
+            // Sort them so we can bind the most important first.
+            Collections.sort(services, SERVICE_SORT);
+        }
+        int i;
+        // Allow mMaxBound items to bind.
+        for (i = 0; i < mMaxBound && i < N; i++) {
+            services.get(i).setBindAllowed(true);
+        }
+        // The rest aren't allowed to bind for now.
+        while (i < N) {
+            services.get(i).setBindAllowed(false);
+            i++;
+        }
+    }
+
+    private void verifyCaller(String packageName) {
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName,
+                    Binder.getCallingUserHandle().getIdentifier());
+            if (Binder.getCallingUid() != uid) {
+                throw new SecurityException("Component outside caller's uid");
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new SecurityException(e);
+        }
+    }
+
+    @Override
+    public void updateQsTile(Tile tile) {
+        verifyCaller(tile.getComponentName().getPackageName());
+        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        if (customTile != null) {
+            mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+            customTile.updateState(tile);
+            customTile.refreshState();
+        }
+    }
+
+    @Override
+    public void onShowDialog(Tile tile) {
+        verifyCaller(tile.getComponentName().getPackageName());
+        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        if (customTile != null) {
+            customTile.onDialogShown();
+            mHost.collapsePanels();
+        }
+    }
+
+    private CustomTile getTileForComponent(ComponentName component) {
+        return mTiles.get(component);
+    }
+
+    private static final Comparator<TileServiceManager> SERVICE_SORT =
+            new Comparator<TileServiceManager>() {
+        @Override
+        public int compare(TileServiceManager left, TileServiceManager right) {
+            return -Integer.compare(left.getBindPriority(), right.getBindPriority());
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index fc802dd..c696f88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -58,8 +58,6 @@
     public void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         setEnabled(!mState.value);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     private void setEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index f73ee35..23a15b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,8 +71,6 @@
     protected void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         mSetting.setValue(mState.value ? 0 : 1);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index d96f735..4f9f46d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -107,8 +107,6 @@
                     Toast.LENGTH_LONG).show();
             return;
         }
-        mDisable.setAllowAnimation(true);
-        mDisableTotalSilence.setAllowAnimation(true);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         if (mState.value) {
             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 12c1298..39d9da1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -64,7 +64,7 @@
         }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         boolean newState = !mState.value;
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
         mFlashlightController.setFlashlight(newState);
     }
 
@@ -73,8 +73,8 @@
         // TODO: Flashlight available handling...
 //        state.visible = mFlashlightController.isAvailable();
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
-        if (arg instanceof UserBoolean) {
-            boolean value = ((UserBoolean) arg).value;
+        if (arg instanceof Boolean) {
+            boolean value = (Boolean) arg;
             if (value == state.value) {
                 return;
             }
@@ -83,7 +83,6 @@
             state.value = mFlashlightController.isEnabled();
         }
         final AnimationIcon icon = state.value ? mEnable : mDisable;
-        icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
         state.icon = icon;
         int onOrOffId = state.value
                 ? R.string.accessibility_quick_settings_flashlight_on
@@ -107,12 +106,12 @@
 
     @Override
     public void onFlashlightChanged(boolean enabled) {
-        refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
+        refreshState(enabled);
     }
 
     @Override
     public void onFlashlightError() {
-        refreshState(UserBoolean.BACKGROUND_FALSE);
+        refreshState(false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 250d567..55aa32b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -59,8 +59,6 @@
         final boolean isEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
         mController.setHotspotEnabled(!isEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 08540f6..e79aabf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -67,8 +67,6 @@
                     mHost.openPanels();
                     MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
                     mController.setLocationEnabled(!wasEnabled);
-                    mEnable.setAllowAnimation(true);
-                    mDisable.setAllowAnimation(true);
                 }
             });
             return;
@@ -76,8 +74,6 @@
         final boolean wasEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
         mController.setLocationEnabled(!wasEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d85cf60..7bce54b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -63,15 +63,14 @@
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         final boolean newState = !mState.value;
         mController.setRotationLocked(newState);
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
     }
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (mController == null) return;
-        final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+        final boolean rotationLocked = arg != null ? (Boolean) arg
                 : mController.isRotationLocked();
-        final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
         // TODO: Handle accessibility rotation lock and whatnot.
 //        state.visible = mController.isRotationLockAffordanceVisible();
         if (state.value == rotationLocked && state.contentDescription != null) {
@@ -80,18 +79,15 @@
         }
         state.value = rotationLocked;
         final boolean portrait = isCurrentOrientationLockPortrait();
-        final AnimationIcon icon;
         if (rotationLocked) {
             final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
                     : R.string.quick_settings_rotation_locked_landscape_label;
             state.label = mContext.getString(label);
-            icon = portrait ? mAutoToPortrait : mAutoToLandscape;
+            state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
         } else {
             state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-            icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
+            state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
         }
-        icon.setAllowAnimation(userInitiated);
-        state.icon = icon;
         state.contentDescription = getAccessibilityString(rotationLocked,
                 R.string.accessibility_rotation_lock_on_portrait,
                 R.string.accessibility_rotation_lock_on_landscape,
@@ -145,8 +141,7 @@
     private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
         @Override
         public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-            refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
+            refreshState(rotationLocked);
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 07915f8..255f29f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -93,12 +93,7 @@
     }
 
     private void refreshQuietModeState(boolean backgroundRefresh) {
-        if (backgroundRefresh) {
-            refreshState(isWorkModeEnabled() ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
-        } else {
-            refreshState(isWorkModeEnabled() ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
-        }
+        refreshState(isWorkModeEnabled());
     }
 
     @Override
@@ -108,28 +103,22 @@
             return;
         }
 
-        final boolean userInitialized;
-        if (arg instanceof UserBoolean) {
-            state.value = ((UserBoolean) arg).value;
-            userInitialized = ((UserBoolean) arg).userInitiated;
+        if (arg instanceof Boolean) {
+            state.value = (Boolean) arg;
         } else {
             state.value = isWorkModeEnabled();
-            userInitialized = false;
         }
 
-        final AnimationIcon icon;
         state.label = mContext.getString(R.string.quick_settings_work_mode_label);
         if (state.value) {
-            icon = mEnable;
+            state.icon = mEnable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_on);
         } else {
-            icon = mDisable;
+            state.icon = mDisable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_off);
         }
-        icon.setAllowAnimation(userInitialized);
-        state.icon = icon;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 7547570f..cfbd1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -74,9 +74,6 @@
     public int svelteLevel;
     public int searchBarSpaceHeightPx;
 
-    /** Dev options and global settings */
-    public boolean lockToAppEnabled;
-
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
@@ -106,12 +103,7 @@
     /**
      * Updates the configuration based on the current state of the system
      */
-    void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
-        // Only update resources that can change after the first load, either through developer
-        // settings or via multi window
-        lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
-                ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
-
+    void update(Rect windowRect) {
         // Recompute some values based on the given state, since we can not rely on the resource
         // system to get certain values.
         boolean isLandscape = windowRect.width() > windowRect.height();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 949fb86..2b988a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -572,7 +572,7 @@
         Rect windowRect = ssp.getWindowRect();
 
         // Update the configuration for the current state
-        config.update(mContext, ssp, ssp.getWindowRect());
+        config.update(windowRect);
 
         if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
             // Try and pre-emptively bind the search widget on startup to ensure that we
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 7a92b2a..d6262ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -155,7 +155,7 @@
             // Add the task to the stack
             Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
                     thumbnail, title, contentDescription, activityColor, !isStackTask,
-                    (i == (taskCount - 1)), config.lockToAppEnabled, t.bounds, t.taskDescription);
+                    t.bounds, t.taskDescription);
 
             allTasks.add(task);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 34a0e52..d030fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -131,8 +131,6 @@
      */
     public boolean isLaunchTarget;
     public boolean isHistorical;
-    public boolean lockToThisTask;
-    public boolean lockToTaskEnabled;
 
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
@@ -142,8 +140,8 @@
 
     public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
                 Bitmap thumbnail, String title, String contentDescription, int colorPrimary,
-                boolean isHistorical, boolean lockToThisTask, boolean lockToTaskEnabled,
-                Rect bounds, ActivityManager.TaskDescription taskDescription) {
+                boolean isHistorical, Rect bounds,
+                ActivityManager.TaskDescription taskDescription) {
         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
         this.key = key;
@@ -159,8 +157,6 @@
         this.bounds = bounds;
         this.taskDescription = taskDescription;
         this.isHistorical = isHistorical;
-        this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
-        this.lockToTaskEnabled = lockToTaskEnabled;
     }
 
     /** Copies the other task. */
@@ -178,8 +174,6 @@
         this.bounds = o.bounds;
         this.isLaunchTarget = o.isLaunchTarget;
         this.isHistorical = o.isHistorical;
-        this.lockToThisTask = o.lockToThisTask;
-        this.lockToTaskEnabled = o.lockToTaskEnabled;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 6f003ab..5e720cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -427,8 +427,6 @@
                 removeGroup(group);
             }
         }
-        // Update the lock-to-app state
-        t.lockToThisTask = false;
     }
 
     /** Removes a task */
@@ -437,9 +435,6 @@
             boolean wasFrontMostTask = (getStackFrontMostTask() == t);
             removeTaskImpl(mStackTaskList, t);
             Task newFrontMostTask = getStackFrontMostTask();
-            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
-                newFrontMostTask.lockToThisTask = true;
-            }
             if (mCb != null) {
                 // Notify that a task has been removed
                 mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
@@ -524,10 +519,21 @@
         mAffinitiesGroups.clear();
     }
 
-    /** Gets the front task */
+    /**
+     * Gets the front-most task in the stack.
+     */
     public Task getStackFrontMostTask() {
-        if (mStackTaskList.size() == 0) return null;
-        return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
+        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+        if (stackTasks.isEmpty()) {
+            return null;
+        }
+        for (int i = stackTasks.size() - 1; i >= 0; i--) {
+            Task task = stackTasks.get(i);
+            if (!task.isFreeformTask()) {
+                return task;
+            }
+        }
+        return null;
     }
 
     /** Gets the task keys */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 830d607..94fae13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,6 +28,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.provider.Settings;
 import android.util.IntProperty;
 import android.util.Log;
 import android.util.Property;
@@ -149,7 +150,9 @@
     List<TaskView> mImmutableTaskViews = new ArrayList<>();
     List<TaskView> mTmpTaskViews = new ArrayList<>();
     LayoutInflater mInflater;
+
     boolean mTouchExplorationEnabled;
+    boolean mScreenPinningEnabled;
 
     Interpolator mFastOutSlowInInterpolator;
 
@@ -224,6 +227,8 @@
     protected void onAttachedToWindow() {
         SystemServicesProxy ssp = Recents.getSystemServices();
         mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+        mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
+                Settings.System.LOCK_TO_APP_ENABLED) != 0;
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
         super.onAttachedToWindow();
     }
@@ -1023,8 +1028,7 @@
                         launchTargetTask);
                 hideTask = launchTargetTask.isFreeformTask() && task.isFreeformTask();
             }
-            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, hideTask, occludesLaunchTarget,
-                    offscreenY);
+            tv.prepareEnterRecentsAnimation(hideTask, occludesLaunchTarget, offscreenY);
         }
 
         // If the enter animation started already and we haven't completed a layout yet, do the
@@ -1087,6 +1091,7 @@
                 ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
                 ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
                         launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
+                ctx.isScreenPinningEnabled = mScreenPinningEnabled;
                 ctx.updateListener = mRequestUpdateClippingListener;
                 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
                         ctx.currentTaskTransform, null);
@@ -1271,13 +1276,11 @@
             requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
         }
 
-        // Update the new front most task
-        if (newFrontMostTask != null) {
+        // Update the new front most task's action button
+        if (mScreenPinningEnabled && newFrontMostTask != null) {
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
-                frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(getResources().getInteger(
-                        R.integer.recents_task_enter_from_app_duration));
+                frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
             }
         }
 
@@ -1304,7 +1307,7 @@
 
     @Override
     public void prepareViewToEnterPool(TaskView tv) {
-        Task task = tv.getTask();
+        final Task task = tv.getTask();
 
         // Report that this tasks's data is no longer being used
         Recents.getTaskLoader().unloadTaskData(task);
@@ -1314,14 +1317,13 @@
         // Update the task views list after removing the task view
         updateTaskViewsList();
 
-        // Reset the view properties
+        // Reset the view properties and view state
         tv.resetViewProperties();
-
-        // Reset the focused view state
         tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-
-        // Reset the clip state of the task view
         tv.setClipViewInStack(false);
+        if (mScreenPinningEnabled) {
+            tv.hideActionButton();
+        }
     }
 
     @Override
@@ -1362,6 +1364,11 @@
         if (mFocusedTask == task) {
             tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
         }
+
+        // Restore the action button visibility if it is the front most task view
+        if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+            tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index a3e8b2d..14909c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -138,6 +138,7 @@
             setBackground(new FakeShadowDrawable(res, config));
         }
         setOutlineProvider(mViewBounds);
+        setOnLongClickListener(this);
     }
 
     /** Set callback */
@@ -175,8 +176,10 @@
             public void getOutline(View view, Outline outline) {
                 // Set the outline to match the FAB background
                 outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
+                outline.setAlpha(0.35f);
             }
         });
+        mActionButtonView.setOnClickListener(this);
         mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
     }
 
@@ -293,8 +296,8 @@
 
     /** Prepares this task view for the enter-recents animations.  This is called earlier in the
      * first layout because the actual animation into recents may take a long time. */
-    void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
-            boolean occludesLaunchTarget, int offscreenY) {
+    void prepareEnterRecentsAnimation(boolean hideTask, boolean occludesLaunchTarget,
+            int offscreenY) {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         int initialDim = getDim();
@@ -303,7 +306,7 @@
         } else if (launchState.launchedHasConfigurationChanged) {
             // Just load the views as-is
         } else if (launchState.launchedFromAppWithThumbnail) {
-            if (isTaskViewLaunchTargetTask) {
+            if (mTask.isLaunchTarget) {
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
                 // Hide the action button
@@ -342,11 +345,15 @@
         if (launchState.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
                 ctx.postAnimationTrigger.increment();
-                // Immediately start the dim animation
+                // Start the dim animation
                 animateDimToProgress(taskViewEnterFromAppDuration,
                         ctx.postAnimationTrigger.decrementOnAnimationEnd());
-                // Animate the action button in
-                fadeInActionButton(taskViewEnterFromAppDuration);
+
+                // Start the action button animation
+                if (ctx.isScreenPinningEnabled) {
+                    showActionButton(true /* fadeIn */,
+                            taskViewEnterFromAppDuration /* fadeInDuration */);
+                }
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
@@ -413,17 +420,6 @@
         animate().cancel();
     }
 
-    public void fadeInActionButton(int duration) {
-        // Hide the action button
-        mActionButtonView.setAlpha(0f);
-
-        // Animate the action button in
-        mActionButtonView.animate().alpha(1f)
-                .setDuration(duration)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN)
-                .start();
-    }
-
     /** Animates this task view as it leaves recents by pressing home. */
     void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
         int taskViewExitToHomeDuration = getResources().getInteger(
@@ -468,8 +464,9 @@
                     .alpha(0f)
                     .setStartDelay(0)
                     .setDuration(taskViewExitToAppDuration)
-                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setInterpolator(PhoneStatusBar.ALPHA_OUT)
                     .withEndAction(postAnimRunnable)
+                    .withLayer()
                     .start();
         } else {
             // Hide the dismiss button
@@ -644,8 +641,6 @@
         setDim(getDimFromTaskProgress());
     }
 
-    /**** View focus state ****/
-
     /**
      * Explicitly sets the focused state of this task.
      */
@@ -672,19 +667,42 @@
         }
     }
 
+    /**
+     * Shows the action button.
+     * @param fadeIn whether or not to animate the action button in.
+     * @param fadeInDuration the duration of the action button animation, only used if
+     *                       {@param fadeIn} is true.
+     */
+    public void showActionButton(boolean fadeIn, int fadeInDuration) {
+        mActionButtonView.setVisibility(View.VISIBLE);
+
+        if (fadeIn) {
+            if (mActionButtonView.getAlpha() < 1f) {
+                mActionButtonView.setAlpha(0f);
+                mActionButtonView.animate().alpha(1f)
+                        .setDuration(fadeInDuration)
+                        .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                        .withLayer()
+                        .start();
+            }
+        } else {
+            mActionButtonView.setAlpha(1f);
+        }
+    }
+
+    /**
+     * Immediately hides the action button.
+     */
+    public void hideActionButton() {
+        mActionButtonView.setVisibility(View.INVISIBLE);
+    }
+
     /**** TaskCallbacks Implementation ****/
 
     /** Binds this task view to the task */
     public void onTaskBound(Task t) {
         mTask = t;
         mTask.addCallback(this);
-
-        // Hide the action button if lock to app is disabled for this view
-        int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
-        if (mActionButtonView.getVisibility() != lockButtonVisibility) {
-            mActionButtonView.setVisibility(lockButtonVisibility);
-            requestLayout();
-        }
     }
 
     @Override
@@ -693,10 +711,6 @@
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask);
             mHeaderView.rebindToTask(mTask);
-
-            // Rebind any listeners
-            mActionButtonView.setOnClickListener(this);
-            setOnLongClickListener(this);
         }
         mTaskDataLoaded = true;
     }
@@ -708,8 +722,6 @@
             mTask.removeCallback(this);
             mThumbnailView.unbindFromTask();
             mHeaderView.unbindFromTask();
-            // Unbind any listeners
-            mActionButtonView.setOnClickListener(null);
         }
         mTaskDataLoaded = false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index e1d80fd..eaef51c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -33,6 +33,8 @@
 
         // These following properties are updated for each task view we start the enter animation on
 
+        // Whether or not screen pinning is enabled
+        boolean isScreenPinningEnabled;
         // Whether or not the current task occludes the launch target
         boolean currentTaskOccludesLaunchTarget;
         // The task rect for the current stack
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1d7651c..11d7b9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -970,7 +970,7 @@
         ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
 
-        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        final View settingsButton = guts.findViewById(R.id.more_settings);
         if (appUid >= 0) {
             final int appUidF = appUid;
             settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -983,6 +983,13 @@
             settingsButton.setVisibility(View.GONE);
         }
 
+        row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissPopups();
+            }
+        });
+
         guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index e6d837a..90a688f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,30 +18,25 @@
 
 import android.app.ActivityManager;
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
-import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
-import android.os.RemoteException;
 import android.provider.Settings;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BatteryTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.CustomTile;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
 import com.android.systemui.qs.tiles.HotspotTile;
@@ -76,7 +71,7 @@
 import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
-public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tunable {
+public final class QSTileHost implements QSTile.Host, Tunable {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -100,6 +95,7 @@
     private final KeyguardMonitor mKeyguard;
     private final SecurityController mSecurity;
     private final BatteryController mBattery;
+    private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
 
@@ -131,6 +127,8 @@
         ht.start();
         mLooper = ht.getLooper();
 
+        mServices = new TileServices(this, mLooper);
+
         TunerService.get(mContext).addTunable(this, TILES_SETTING);
     }
 
@@ -256,6 +254,10 @@
         return mSecurity;
     }
 
+    public TileServices getTileServices() {
+        return mServices;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
@@ -306,50 +308,6 @@
                 TextUtils.join(",", specs), ActivityManager.getCurrentUser());
     }
 
-    @Override
-    public void updateQsTile(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.updateState(tile);
-            customTile.refreshState();
-        }
-    }
-
-    @Override
-    public void onShowDialog(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.onDialogShown();
-            collapsePanels();
-        }
-    }
-
-    private void verifyCaller(String packageName) {
-        try {
-            int uid = mContext.getPackageManager().getPackageUid(packageName,
-                    Binder.getCallingUserHandle().getIdentifier());
-            if (Binder.getCallingUid() != uid) {
-                throw new SecurityException("Component outside caller's uid");
-            }
-        } catch (NameNotFoundException e) {
-            throw new SecurityException(e);
-        }
-    }
-
-    private CustomTile getTileForComponent(ComponentName component) {
-        // TODO: Build map for easier lookup.
-        for (QSTile<?> qsTile : mTiles.values()) {
-            if (qsTile instanceof CustomTile) {
-                if (((CustomTile) qsTile).getComponent().equals(component)) {
-                    return (CustomTile) qsTile;
-                }
-            }
-        }
-        return null;
-    }
-
     public QSTile<?> createTile(String tileSpec) {
         if (tileSpec.equals("wifi")) return WifiTile.isSupported(this)
                 ? new WifiTile(this) : null;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 1e3b0f1..9081af1 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -153,8 +153,11 @@
     private static TunerService sInstance;
 
     public static TunerService get(Context context) {
-        SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
-        TunerService service = sysUi.getComponent(TunerService.class);
+        TunerService service = null;
+        if (context.getApplicationContext() instanceof SystemUIApplication) {
+            SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
+            service = sysUi.getComponent(TunerService.class);
+        }
         if (service == null) {
             // Can't get it as a component, must in the tuner, lets just create one for now.
             return getStaticService(context);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cd47ac1..38d8de0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -510,7 +510,7 @@
         GregorianCalendar weekRange = new GregorianCalendar();
         final long now = weekRange.getTimeInMillis();
         setToMidnight(weekRange);
-        weekRange.roll(Calendar.DATE, 6);
+        weekRange.add(Calendar.DATE, 6);
         final long nextAlarmMs = mController.getNextAlarm();
         if (nextAlarmMs > 0) {
             GregorianCalendar nextAlarm = new GregorianCalendar();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c21af24..2825601 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -19,10 +19,16 @@
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
+
+        <service
+            android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
+            android:process=":killable" />
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
new file mode 100644
index 0000000..0594211
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.external;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.UserHandle;
+import android.service.quicksettings.TileService;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+public class TileLifecycleManagerTests extends AndroidTestCase {
+    public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
+    public static final String EXTRA_CALLBACK = "callback";
+
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileLifecycleManager mStateManager;
+    private final Object mBroadcastLock = new Object();
+    private final ArraySet<String> mCallbacks = new ArraySet<>();
+    private boolean mBound;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mStateManager = new TileLifecycleManager(mHandler, getContext(),
+                new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+        mCallbacks.clear();
+        getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (mBound) {
+            unbindService();
+        }
+        mThread.quit();
+        getContext().unregisterReceiver(mReceiver);
+    }
+
+    public void testSync() {
+        syncWithHandler();
+    }
+
+    public void testBind() {
+        bindService();
+        waitForCallback("onCreate");
+    }
+
+    public void testUnbind() {
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+    }
+
+    public void testTileServiceCallbacks() {
+        bindService();
+        waitForCallback("onCreate");
+
+        mStateManager.onTileAdded();
+        waitForCallback("onTileAdded");
+        mStateManager.onStartListening();
+        waitForCallback("onStartListening");
+        mStateManager.onClick(null);
+        waitForCallback("onClick");
+        mStateManager.onStopListening();
+        waitForCallback("onStopListening");
+        mStateManager.onTileRemoved();
+        waitForCallback("onTileRemoved");
+
+        unbindService();
+    }
+
+    public void testAddedBeforeBind() {
+        mStateManager.onTileAdded();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+    }
+
+    public void testListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+    }
+
+    public void testClickBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+        waitForCallback("onClick");
+    }
+
+    public void testListeningNotListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onStartListening"));
+    }
+
+    public void testNoClickOfNotListeningAnymore() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onClick"));
+    }
+
+    public void testComponentEnabling() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        PackageManager pm = getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+        bindService();
+        assertTrue(mStateManager.mReceiverRegistered);
+
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+        waitForCallback("onCreate");
+    }
+
+    public void testKillProcess() {
+        mStateManager.onStartListening();
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+
+        getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
+
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+    }
+
+    private void bindService() {
+        mBound = true;
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        mBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    private void waitForCallback(String callback) {
+        for (int i = 0; i < 25; i++) {
+            if (mCallbacks.contains(callback)) {
+                mCallbacks.remove(callback);
+                return;
+            }
+            synchronized (mBroadcastLock) {
+                try {
+                    mBroadcastLock.wait(500);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        if (mCallbacks.contains(callback)) {
+            mCallbacks.remove(callback);
+            return;
+        }
+        fail("Didn't receive callback: " + callback);
+    }
+
+    private void syncWithHandler() {
+        final Object lock = new Object();
+        synchronized (lock) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (lock) {
+                        lock.notify();
+                    }
+                }
+            });
+            try {
+                lock.wait(5000);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
+            synchronized (mBroadcastLock) {
+                mBroadcastLock.notify();
+            }
+        }
+    };
+
+    public static class FakeTileService extends TileService {
+        public static final String ACTION_KILL = "com.android.systemui.test.KILL";
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
+            sendCallback("onCreate");
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+            unregisterReceiver(mReceiver);
+            sendCallback("onDestroy");
+        }
+
+        @Override
+        public void onTileAdded() {
+            sendCallback("onTileAdded");
+        }
+
+        @Override
+        public void onTileRemoved() {
+            sendCallback("onTileRemoved");
+        }
+
+        @Override
+        public void onStartListening() {
+            sendCallback("onStartListening");
+        }
+
+        @Override
+        public void onStopListening() {
+            sendCallback("onStopListening");
+        }
+
+        @Override
+        public void onClick() {
+            sendCallback("onClick");
+        }
+
+        private void sendCallback(String callback) {
+            Log.d("TileLifecycleManager", "Relaying: " + callback);
+            sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
+                    .putExtra(EXTRA_CALLBACK, callback));
+        }
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (ACTION_KILL.equals(intent.getAction())) {
+                    Process.killProcess(Process.myPid());
+                }
+            }
+        };
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
new file mode 100644
index 0000000..c4f686e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import com.android.systemui.SysuiTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class TileServiceManagerTests extends SysuiTestCase {
+
+    private TileServices mTileServices;
+    private TileLifecycleManager mTileLifecycle;
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileServiceManager mTileServiceManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mTileServices = Mockito.mock(TileServices.class);
+        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+        mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mThread.quit();
+    }
+
+    public void testSetBindRequested() {
+        // Request binding.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setLastUpdate(0);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        assertEquals(5, mTileServiceManager.getBindPriority());
+
+        // Verify same state doesn't trigger recalculating for no reason.
+        mTileServiceManager.setBindRequested(true);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+        assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testPendingClickPriority() {
+        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+        mTileServiceManager.calculateBindPriority(0);
+        assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testBind() {
+        // Trigger binding requested and allowed.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setBindAllowed(true);
+
+        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+        assertTrue((boolean) captor.getValue());
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(0);
+        // Priority shouldn't disappear after the request goes away if we just bound, instead
+        // it sticks around to avoid thrashing a bunch of processes.
+        assertEquals(Integer.MAX_VALUE - 1, mTileServiceManager.getBindPriority());
+
+        mTileServiceManager.setBindAllowed(false);
+        captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+        assertFalse((boolean) captor.getValue());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
new file mode 100644
index 0000000..7a3ce87
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Looper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+public class TileServicesTests extends SysuiTestCase {
+    private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+    private TileServices mTileService;
+    private ArrayList<TileServiceManager> mManagers;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mManagers = new ArrayList<>();
+        QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+                null, null, null, null, null, null);
+        mTileService = new TestTileServices(host, Looper.myLooper());
+    }
+
+    public void testRecalculateBindAllowance() {
+        // Add some fake tiles.
+        for (int i = 0; i < NUM_FAKES; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        assertEquals(NUM_FAKES, mManagers.size());
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+        }
+        mTileService.recalculateBindAllowance();
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+                    Mockito.anyLong());
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testSetMemoryPressure() {
+        testRecalculateBindAllowance();
+        mTileService.setMemoryPressure(true);
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testCalcFew() {
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        mTileService.recalculateBindAllowance();
+
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            // Shouldn't get bind prioirities calculated when there are less than the max services.
+            Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+                    Mockito.anyLong());
+
+            // All should be bound since there are less than the max services.
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertTrue(captor.getValue());
+        }
+    }
+
+    private class TestTileServices extends TileServices {
+        public TestTileServices(QSTileHost host, Looper looper) {
+            super(host, looper);
+        }
+
+        @Override
+        protected TileServiceManager onCreateTileService(ComponentName component) {
+            TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+            mManagers.add(manager);
+            return manager;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3e8dc4e..1c25067 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2743,9 +2743,9 @@
         return mAppBindArgs;
     }
 
-    final void setFocusedActivityLocked(ActivityRecord r, String reason) {
+    boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
         if (r == null || mFocusedActivity == r) {
-            return;
+            return false;
         }
 
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
@@ -2783,7 +2783,7 @@
                 finishVoiceTask(last.task.voiceSession);
             }
         }
-        if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+        if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
             mWindowManager.setFocusedApp(r.appToken, true);
         }
         applyUpdateLockStateLocked(r);
@@ -2799,23 +2799,35 @@
                 mFocusedActivity == null ? -1 : mFocusedActivity.userId,
                 mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
                 reason);
+        return true;
     }
 
-    final void clearFocusedActivity(ActivityRecord r) {
-        if (mFocusedActivity == r) {
-            ActivityStack stack = mStackSupervisor.getFocusedStack();
-            if (stack != null) {
-                ActivityRecord top = stack.topActivity();
-                if (top != null && top.userId != mLastFocusedUserId) {
-                    mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
-                    mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
-                                    top.userId, 0));
-                    mLastFocusedUserId = top.userId;
-                }
-            }
-            mFocusedActivity = null;
-            EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
+    final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
+        if (mFocusedActivity != goingAway) {
+            return;
         }
+
+        final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+        if (focusedStack != null) {
+            final ActivityRecord top = focusedStack.topActivity();
+            if (top != null && top.userId != mLastFocusedUserId) {
+                mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
+                mLastFocusedUserId = top.userId;
+            }
+        }
+
+        // Try to move focus to another activity if possible.
+        if (setFocusedActivityLocked(
+                focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
+            return;
+        }
+
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
+                + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
+        mFocusedActivity = null;
+        EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
     }
 
     @Override
@@ -2827,7 +2839,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked();
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
-                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -2844,7 +2856,7 @@
                     ActivityRecord r = task.topRunningActivityLocked();
                     if (r != null) {
                         setFocusedActivityLocked(r, "setFocusedTask");
-                        mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+                        mStackSupervisor.resumeFocusedStackTopActivityLocked();
                     }
                 }
             }
@@ -3590,7 +3602,7 @@
     Intent getHomeIntent() {
         Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
         intent.setComponent(mTopComponent);
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             intent.addCategory(Intent.CATEGORY_HOME);
         }
@@ -4473,7 +4485,7 @@
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false)) {
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -4811,12 +4823,11 @@
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
 
-        if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
-            // If there was nothing to resume, and we are not already
-            // restarting this process, but there is a visible activity that
-            // is hosted by the process...  then make sure all visible
-            // activities are running, taking care of restarting this
-            // process.
+        if (!restarting && hasVisibleActivities
+                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+            // If there was nothing to resume, and we are not already restarting this process, but
+            // there is a visible activity that is hosted by the process...  then make sure all
+            // visible activities are running, taking care of restarting this process.
             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         }
     }
@@ -5873,7 +5884,7 @@
         // Clean-up disabled activities.
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                 packageName, disabledClasses, true, false, userId) && mBooted) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mStackSupervisor.scheduleIdleLocked();
         }
 
@@ -6061,7 +6072,7 @@
                 }
             }
             if (mBooted) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 mStackSupervisor.scheduleIdleLocked();
             }
         }
@@ -8994,7 +9005,7 @@
                 task.mResizeable = resizeable;
                 mWindowManager.setTaskResizeable(taskId, resizeable);
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
         }
     }
@@ -9802,7 +9813,7 @@
             ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
                     .queryContentProviders(app.processName, app.uid,
                             STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
-                                    | PackageManager.MATCH_ENCRYPTION_DEFAULT);
+                                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
             providers = slice != null ? slice.getList() : null;
         } catch (RemoteException ex) {
         }
@@ -12603,7 +12614,7 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
         }
     }
@@ -12714,10 +12725,10 @@
                 // annoy the user repeatedly.  Unless it is persistent, since those
                 // processes run critical code.
                 removeProcessLocked(app, false, false, "crash");
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return false;
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } else {
             mStackSupervisor.finishTopRunningActivityLocked(app, reason);
         }
@@ -17010,7 +17021,7 @@
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
             int callingUid, int[] users) {
         // TODO: come back and remove this assumption to triage all broadcasts
-        int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_ENCRYPTION_DEFAULT;
+        int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 
         List<ResolveInfo> receivers = null;
         try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1492e23..b9ff32c 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -572,6 +572,10 @@
         }
     }
 
+    boolean isFocusable() {
+        return StackId.canReceiveKeys(mStackId);
+    }
+
     final boolean isAttached() {
         return mStacks != null;
     }
@@ -917,7 +921,7 @@
         if (prev == null) {
             if (!resuming) {
                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -1008,7 +1012,7 @@
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
             if (!resuming) {
-                mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -1075,7 +1079,7 @@
             } else {
                 if (r.configDestroy) {
                     destroyActivityLocked(r, true, "stop-config");
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 } else {
                     mStackSupervisor.updatePreviousProcessLocked(r);
                 }
@@ -1131,17 +1135,16 @@
         if (resumeNext) {
             final ActivityStack topStack = mStackSupervisor.getFocusedStack();
             if (!mService.isSleepingOrShuttingDown()) {
-                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
             } else {
                 mStackSupervisor.checkReadyForSleepLocked();
                 ActivityRecord top = topStack.topRunningActivityLocked();
                 if (top == null || (prev != null && top != prev)) {
-                    // If there are no more activities available to run,
-                    // do resume anyway to start something.  Also if the top
-                    // activity on the stack is not the just paused activity,
-                    // we need to go ahead and resume it to ensure we complete
-                    // an in-flight app switch.
-                    mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
+                    // If there are no more activities available to run, do resume anyway to start
+                    // something. Also if the top activity on the stack is not the just paused
+                    // activity, we need to go ahead and resume it to ensure we complete an
+                    // in-flight app switch.
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -1478,7 +1481,7 @@
         boolean aboveTop = top != null;
         final boolean stackInvisible = !isStackVisibleLocked();
         boolean behindFullscreenActivity = stackInvisible;
-        boolean noStackActivityResumed = (isInStackLocked(starting) == null);
+        boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1509,18 +1512,18 @@
 
                     if (r.app == null || r.app.thread == null) {
                         if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
-                                noStackActivityResumed, r)) {
+                                resumeNextActivity, r)) {
                             if (activityNdx >= activities.size()) {
                                 // Record may be removed if its process needs to restart.
                                 activityNdx = activities.size() - 1;
                             } else {
-                                noStackActivityResumed = false;
+                                resumeNextActivity = false;
                             }
                         }
                     } else if (r.visible) {
                         // If this activity is already visible, then there is nothing to do here.
                         if (handleAlreadyVisible(r)) {
-                            noStackActivityResumed = false;
+                            resumeNextActivity = false;
                         }
                     } else {
                         makeVisible(starting, r);
@@ -1561,7 +1564,7 @@
     }
 
     private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
-            boolean isTop, boolean noStackActivityResumed, ActivityRecord r) {
+            boolean isTop, boolean andResume, ActivityRecord r) {
         // We need to make sure the app is running if it's the top, or it is just made visible from
         // invisible. If the app is already visible, it must have died while it was visible. In this
         // case, we'll show the dead window but will not restart the app. Otherwise we could end up
@@ -1578,7 +1581,7 @@
                 setVisible(r, true);
             }
             if (r != starting) {
-                mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+                mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
                 return true;
             }
         }
@@ -1772,15 +1775,17 @@
      *
      * @param prev The previously resumed activity, for when in the process
      * of pausing; can be null to call from elsewhere.
+     * @param options Activity options.
      *
      * @return Returns true if something is being resumed, or false if
      * nothing happened.
+     *
+     * NOTE: It is not safe to call this method directly as it can cause an activity in a
+     *       non-focused stack to be resumed.
+     *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
+     *       right activity for the current system state.
      */
-    final boolean resumeTopActivityLocked(ActivityRecord prev) {
-        return resumeTopActivityLocked(prev, null);
-    }
-
-    final boolean resumeTopActivityLocked(ActivityRecord prev, ActivityOptions options) {
+    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
         if (mStackSupervisor.inResumeTopActivity) {
             // Don't even start recursing.
             return false;
@@ -1836,7 +1841,7 @@
                 // stack is not covering the entire screen.
                 final ActivityStack stack = getNextVisibleStackLocked();
                 if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
-                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
+                    return mStackSupervisor.resumeFocusedStackTopActivityLocked(stack, prev, null);
                 }
             }
             // Let's just start up the Launcher...
@@ -2897,10 +2902,7 @@
             }
         }
 
-        final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
-        if (top != null) {
-            mService.setFocusedActivityLocked(top, myReason);
-        }
+        mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
     }
 
     private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
@@ -2909,12 +2911,7 @@
         if (stack == null) {
             return false;
         }
-        final ActivityRecord top = stack.topRunningActivityLocked();
-        if (top == null) {
-            return false;
-        }
-        mService.setFocusedActivityLocked(top, myReason);
-        return true;
+        return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
     }
 
     final void stopActivityLocked(ActivityRecord r) {
@@ -3224,7 +3221,7 @@
             r.makeFinishingLocked();
             boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
             if (activityRemoved) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                     "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3237,7 +3234,7 @@
         if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
         mStackSupervisor.mFinishingActivities.add(r);
         r.resumeKeyDispatchingLocked();
-        mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return r;
     }
 
@@ -3395,7 +3392,7 @@
         if (mPausingActivity == r) {
             mPausingActivity = null;
         }
-        mService.clearFocusedActivity(r);
+        mService.resetFocusedActivityIfNeededLocked(r);
 
         r.configDestroy = false;
         r.frozenBeforeDestroy = false;
@@ -3526,7 +3523,7 @@
             }
         }
         if (activityRemoved) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3700,7 +3697,7 @@
                     removeActivityFromHistoryLocked(r, reason);
                 }
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -3738,7 +3735,7 @@
             setVisibleBehindActivity(null);
             mStackSupervisor.scheduleIdleTimeoutLocked(null);
         }
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
     }
 
     boolean hasVisibleBehindActivity() {
@@ -3953,7 +3950,7 @@
             updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
 
         if (VALIDATE_TOKENS) {
@@ -4016,7 +4013,7 @@
             if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
                 final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
                 mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
-                mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return true;
             }
         }
@@ -4071,7 +4068,7 @@
             return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return true;
     }
 
@@ -4734,10 +4731,7 @@
 
     private void postAddTask(TaskRecord task, ActivityStack prevStack) {
         if (prevStack != null) {
-            if (prevStack != this
-                    && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
-                task.reportPictureInPictureModeChange();
-            }
+            task.reportPictureInPictureModeChangeIfNeeded(prevStack);
         } else if (task.voiceSession != null) {
             try {
                 task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4758,25 +4752,21 @@
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
-    void setFocusAndResumeStateIfNeeded(
-            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
-        // If the activity had focus before move focus to this stack.
-        if (setFocus) {
-            // If the activity owns the last resumed activity, transfer that together,
-            // so that we don't resume the same activity again in the new stack.
-            // Apps may depend on onResume()/onPause() being called in pairs.
-            if (setResume) {
-                mResumedActivity = r;
-                // Move the stack in which we are placing the activity to the front. We don't use
-                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
-                // already focused, the call will short-circuit and do nothing.
-                moveToFront(reason);
-            } else {
-                // We need to not only move the stack to the front, but also have the activity
-                // focused. This will achieve both goals.
-                mService.setFocusedActivityLocked(r, reason);
-            }
+    void moveToFrontAndResumeStateIfNeeded(
+            ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+        if (!moveToFront) {
+            return;
         }
+
+        // If the activity owns the last resumed activity, transfer that together,
+        // so that we don't resume the same activity again in the new stack.
+        // Apps may depend on onResume()/onPause() being called in pairs.
+        if (setResume) {
+            mResumedActivity = r;
+        }
+        // Move the stack in which we are placing the activity to the front. The call will also
+        // make sure the activity focus is set.
+        moveToFront(reason);
     }
 
     /**
@@ -4800,8 +4790,11 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
-        task.reportPictureInPictureModeChange();
-        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        task.reportPictureInPictureModeChangeIfNeeded(prevStack);
+        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        if (wasResumed) {
+            prevStack.mResumedActivity = null;
+        }
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 32671acf..df1aa52 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -370,7 +370,7 @@
      */
     private LockTaskNotify mLockTaskNotify;
 
-    /** Used to keep resumeTopActivityLocked() from being entered recursively */
+    /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
     // temp. rects used during resize calculation so we don't need to create a new object each time.
@@ -537,16 +537,25 @@
         return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
     }
 
+    /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
     void setFocusStack(String reason, ActivityStack focusedStack) {
-        mLastFocusedStack = mFocusedStack;
-        mFocusedStack = focusedStack;
+        if (focusedStack != mFocusedStack) {
+            mLastFocusedStack = mFocusedStack;
+            mFocusedStack = focusedStack;
 
-        EventLogTags.writeAmFocusedStack(
-                mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
-                mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+            EventLogTags.writeAmFocusedStack(
+                    mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+                    mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+        }
+
+        final ActivityRecord r = topRunningActivityLocked();
+        if (mService.mFocusedActivity != r) {
+            // The focus activity should always be the top activity in the focused stack.
+            // There will be chaos and anarchy if it isn't...
+            mService.setFocusedActivityLocked(r, reason + " setFocusStack");
+        }
 
         if (mService.mBooting || !mService.mBooted) {
-            final ActivityRecord r = topRunningActivityLocked();
             if (r != null && r.idle) {
                 checkFinishBootingLocked();
             }
@@ -591,12 +600,14 @@
 
         mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
         ActivityRecord r = getHomeActivity();
+        final String myReason = reason + " resumeHomeStackTask";
+
         // Only resume home activity if isn't finishing.
         if (r != null && !r.finishing) {
-            mService.setFocusedActivityLocked(r, reason);
-            return resumeTopActivitiesLocked(mHomeStack, prev, null);
+            mService.setFocusedActivityLocked(r, myReason);
+            return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
         }
-        return mService.startHomeActivityLocked(mCurrentUser, reason);
+        return mService.startHomeActivityLocked(mCurrentUser, myReason);
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
@@ -1148,14 +1159,12 @@
             // a resume.
             stack.minimalResumeActivityLocked(r);
         } else {
-            // This activity is not starting in the resumed state... which
-            // should look like we asked it to pause+stop (but remain visible),
-            // and it has done so and reported back the current icicle and
-            // other state.
+            // This activity is not starting in the resumed state... which should look like we asked
+            // it to pause+stop (but remain visible), and it has done so and reported back the
+            // current icicle and other state.
             if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Moving to STOPPED: " + r + " (starting in stopped state)");
-            r.state = STOPPED;
-            r.stopped = true;
+                    "Moving to PAUSED: " + r + " (starting in paused state)");
+            r.state = PAUSED;
         }
 
         // Launch the new version setup screen if needed.  We do this -after-
@@ -1345,14 +1354,14 @@
         return ACTIVITY_RESTRICTION_NONE;
     }
 
-    boolean setFocusedStack(ActivityRecord r, String reason) {
+    boolean moveActivityStackToFront(ActivityRecord r, String reason) {
         if (r == null) {
             // Not sure what you are trying to do, but it is not going to work...
             return false;
         }
         final TaskRecord task = r.task;
         if (task == null || task.stack == null) {
-            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
             return false;
         }
         task.stack.moveToFront(reason, task);
@@ -1518,7 +1527,7 @@
         //mWindowManager.dump();
 
         if (activityRemoved) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
 
         return r;
@@ -1611,35 +1620,17 @@
         }
     }
 
-    boolean resumeTopActivitiesLocked() {
-        return resumeTopActivitiesLocked(null, null, null);
+    boolean resumeFocusedStackTopActivityLocked() {
+        return resumeFocusedStackTopActivityLocked(null, null, null);
     }
 
-    boolean resumeTopActivitiesLocked(
+    boolean resumeFocusedStackTopActivityLocked(
             ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
-        if (targetStack == null) {
-            targetStack = mFocusedStack;
+        if (targetStack != null && isFocusedStack(targetStack)) {
+            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
-        // Do targetStack first.
-        boolean result = false;
-        if (isFocusedStack(targetStack)) {
-            result = targetStack.resumeTopActivityLocked(target, targetOptions);
-        }
-
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
-                if (stack == targetStack) {
-                    // Already started above.
-                    continue;
-                }
-                if (isFocusedStack(stack)) {
-                    stack.resumeTopActivityLocked(null);
-                }
-            }
-        }
-        return result;
+        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        return false;
     }
 
     void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
@@ -1905,7 +1896,7 @@
                 // are made visible with the correct configuration.
                 ensureActivitiesVisibleLocked(r, 0, preserveWindows);
                 if (!updated) {
-                    resumeTopActivitiesLocked(stack, null, null);
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         } finally {
@@ -1961,7 +1952,7 @@
                 // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
                 if (!kept) {
-                    resumeTopActivitiesLocked(stack, null, null);
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -2083,8 +2074,14 @@
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
         final ActivityRecord r = task.getTopActivity();
-        final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
-        final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+        final ActivityStack prevStack = task.stack;
+        final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+        // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+        // Whenever we are moving the top activity from the front stack we want to make sure to move
+        // the stack to the front.
+        final boolean wasFront = isFrontStack(prevStack)
+                && (prevStack.topRunningActivityLocked() == r);
 
         final boolean resizeable = task.mResizeable;
         // Temporarily disable resizeablility of task we are moving. We don't want it to be resized
@@ -2097,9 +2094,9 @@
         stack.addTask(task, toTop, reason);
 
         // If the task had focus before (or we're requested to move focus),
-        // move focus to the new stack.
-        stack.setFocusAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused, wasResumed, reason);
+        // move focus to the new stack by moving the stack to the front.
+        stack.moveToFrontAndResumeStateIfNeeded(
+                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
 
         return stack;
     }
@@ -2149,7 +2146,7 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
 
         if (!task.mResizeable && isStackDockedInEffect(stackId)) {
             showNonResizeableDockToast(taskId);
@@ -2200,7 +2197,7 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
     }
 
     void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -2219,7 +2216,7 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
     }
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
@@ -2329,7 +2326,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 stack.awakeFromSleepingLocked();
                 if (isFocusedStack(stack)) {
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -3124,7 +3121,7 @@
                     if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
                             "setLockTaskModeLocked: Tasks remaining, can't unlock");
                     lockedTask.performClearTaskLocked();
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                     return;
                 }
             }
@@ -3165,7 +3162,7 @@
 
         if (andResume) {
             findTaskToMoveToFrontLocked(task, 0, null, reason);
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3233,7 +3230,7 @@
             didSomething = true;
         }
         if (didSomething) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3280,7 +3277,7 @@
                 } break;
                 case RESUME_TOP_ACTIVITY_MSG: {
                     synchronized (mService) {
-                        resumeTopActivitiesLocked();
+                        resumeFocusedStackTopActivityLocked();
                     }
                 } break;
                 case SLEEP_TIMEOUT_MSG: {
@@ -3661,7 +3658,7 @@
 
             mSurface = surface;
             if (surface != null) {
-                mStack.resumeTopActivityLocked(null);
+                resumeFocusedStackTopActivityLocked();
             } else {
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b16e160..bcb2215 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -916,7 +916,7 @@
                 // is the case, so this is it!  And for paranoia, make
                 // sure we have correctly resumed the top activity.
                 if (doResume) {
-                    mSupervisor.resumeTopActivitiesLocked(targetStack, null, options);
+                    mSupervisor.resumeFocusedStackTopActivityLocked(targetStack, null, options);
 
                     // Make sure to notify Keyguard as well if we are not running an app
                     // transition later.
@@ -1019,7 +1019,7 @@
                 // don't use that intent!)  And for paranoia, make
                 // sure we have correctly resumed the top activity.
                 if (doResume) {
-                    targetStack.resumeTopActivityLocked(null, options);
+                    mSupervisor.resumeFocusedStackTopActivityLocked(targetStack, null, options);
                     if (!movedToFront) {
                         // Make sure to notify Keyguard as well if we are not running an app
                         // transition later.
@@ -1055,7 +1055,7 @@
                 // For paranoia, make sure we have correctly resumed the top activity.
                 topStack.mLastPausedActivity = null;
                 if (doResume) {
-                    mSupervisor.resumeTopActivitiesLocked();
+                    mSupervisor.resumeFocusedStackTopActivityLocked();
                 }
                 ActivityOptions.abort(options);
                 if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -1157,7 +1157,7 @@
                     // resumed the top activity.
                     targetStack.mLastPausedActivity = null;
                     if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
+                        mSupervisor.resumeFocusedStackTopActivityLocked();
                     }
                     ActivityOptions.abort(options);
                     return ActivityManager.START_DELIVERED_TO_TOP;
@@ -1176,7 +1176,7 @@
                     top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                     targetStack.mLastPausedActivity = null;
                     if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
+                        mSupervisor.resumeFocusedStackTopActivityLocked();
                     }
                     return ActivityManager.START_DELIVERED_TO_TOP;
                 }
@@ -1266,9 +1266,11 @@
         targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
         if (doResume) {
             if (!launchTaskBehind) {
+                // TODO: Remove this code after verification that all the decision points above
+                // moved targetStack to the front which will also set the focus activity.
                 mService.setFocusedActivityLocked(r, "startedActivity");
             }
-            mSupervisor.resumeTopActivitiesLocked(targetStack, r, options);
+            mSupervisor.resumeFocusedStackTopActivityLocked(targetStack, r, options);
         } else {
             targetStack.addRecentActivityLocked(r);
         }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4647d77..e77bb20 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1321,7 +1321,12 @@
         }
     }
 
-    void reportPictureInPictureModeChange() {
+    void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) {
+        if (prevStack == null || prevStack == stack
+                || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
+            return;
+        }
+
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
             if (r.app != null && r.app.thread != null) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 20b1e60..f2c5206 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -304,7 +304,10 @@
                         + relatedUserId);
                 // We still need to stop the requested user if it's a force stop.
                 if (force) {
+                    Slog.i(TAG,
+                            "Force stop user " + userId + ". Related users will not be stopped");
                     stopSingleUserLocked(userId, callback);
+                    return USER_OP_SUCCESS;
                 }
                 return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
             }
@@ -931,7 +934,7 @@
         if (homeInFront) {
             mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
         } else {
-            mService.mStackSupervisor.resumeTopActivitiesLocked();
+            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
         getUserManager().onUserForeground(newUserId);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c5e6e7c..4eabe36 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -161,8 +161,9 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Slog.d(TAG, "Receieved: " + intent.getAction());
-            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+            final String action = intent.getAction();
+            Slog.d(TAG, "Receieved: " + action);
+            if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                 // If this is an outright uninstall rather than the first half of an
                 // app update sequence, cancel the jobs associated with the app.
                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
@@ -172,18 +173,21 @@
                     }
                     cancelJobsForUid(uidRemoved, true);
                 }
-            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DEBUG) {
                     Slog.d(TAG, "Removing jobs for user: " + userId);
                 }
                 cancelJobsForUser(userId);
-            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
-                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
+                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
                 updateIdleMode(mPowerManager != null
                         ? (mPowerManager.isDeviceIdleMode()
                                 || mPowerManager.isLightDeviceIdleMode())
                         : false);
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+                // Kick off pending jobs for any apps that re-appeared
+                mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
             }
         }
     };
@@ -425,17 +429,24 @@
     @Override
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
-            // Register br for package removals and user removals.
+            // Register for package removals and user removals.
             final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
             filter.addDataScheme("package");
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
             final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
             userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
             userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
-            mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
+
+            final IntentFilter storageFilter = new IntentFilter();
+            storageFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            getContext().registerReceiverAsUser(
+                    mBroadcastReceiver, UserHandle.ALL, storageFilter, null, null);
+
+            mPowerManager = getContext().getSystemService(PowerManager.class);
             try {
                 ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
                         ActivityManager.UID_OBSERVER_IDLE);
@@ -834,7 +845,7 @@
             final boolean componentPresent;
             try {
                 componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                        job.getServiceComponent(), PackageManager.MATCH_ENCRYPTION_DEFAULT,
+                        job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                         userId) != null);
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
@@ -924,8 +935,8 @@
             final IPackageManager pm = AppGlobals.getPackageManager();
             final ComponentName service = job.getService();
             try {
-                ServiceInfo si = pm.getServiceInfo(service, PackageManager.MATCH_ENCRYPTION_DEFAULT,
-                        UserHandle.getUserId(uid));
+                ServiceInfo si = pm.getServiceInfo(service,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
                 if (si == null) {
                     throw new IllegalArgumentException("No such service " + service);
                 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 1987214..ce18818 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -121,6 +121,11 @@
     }
 
     @Override
+    protected boolean checkType(IInterface service) {
+        return service instanceof IConditionProvider;
+    }
+
+    @Override
     public void onBootPhaseAppsCanStart() {
         super.onBootPhaseAppsCanStart();
         for (int i = 0; i < mSystemConditionProviders.size(); i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b7662da..09e6647 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -141,6 +141,8 @@
 
     abstract protected IInterface asInterface(IBinder binder);
 
+    abstract protected boolean checkType(IInterface service);
+
     abstract protected void onServiceAdded(ManagedServiceInfo info);
 
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -169,7 +171,8 @@
             if (filter != null && !filter.matches(info.component)) continue;
             pw.println("      " + info.component
                     + " (user " + info.userid + "): " + info.service
-                    + (info.isSystem?" SYSTEM":""));
+                    + (info.isSystem?" SYSTEM":"")
+                    + (info.isGuest(this)?" GUEST":""));
         }
     }
 
@@ -266,6 +269,18 @@
         }
     }
 
+    /**
+     * Add a service to our callbacks. The lifecycle of this service is managed externally,
+     * but unlike a system service, it should not be considered privledged.
+     * */
+    public void registerGuestService(ManagedServiceInfo guest) {
+        checkNotNull(guest.service);
+        checkType(guest.service);
+        if (registerServiceImpl(guest) != null) {
+            onServiceAdded(guest);
+        }
+    }
+
     public void setCategoryState(String category, boolean enabled) {
         synchronized (mMutex) {
             final Boolean previous = mCategoryEnabled.put(category, enabled);
@@ -484,7 +499,7 @@
         synchronized (mMutex) {
             // Unbind automatically bound services, retain system services.
             for (ManagedServiceInfo service : mServices) {
-                if (!service.isSystem) {
+                if (!service.isSystem && !service.isGuest(this)) {
                     toRemove.add(service);
                 }
             }
@@ -709,11 +724,15 @@
 
     private ManagedServiceInfo registerServiceImpl(final IInterface service,
             final ComponentName component, final int userid) {
+        ManagedServiceInfo info = newServiceInfo(service, component, userid,
+                true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
+        return registerServiceImpl(info);
+    }
+
+    private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
         synchronized (mMutex) {
             try {
-                ManagedServiceInfo info = newServiceInfo(service, component, userid,
-                        true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
-                service.asBinder().linkToDeath(info, 0);
+                info.service.asBinder().linkToDeath(info, 0);
                 mServices.add(info);
                 return info;
             } catch (RemoteException e) {
@@ -728,7 +747,7 @@
      */
     private void unregisterServiceImpl(IInterface service, int userid) {
         ManagedServiceInfo info = removeServiceImpl(service, userid);
-        if (info != null && info.connection != null) {
+        if (info != null && info.connection != null && !info.isGuest(this)) {
             mContext.unbindService(info.connection);
         }
     }
@@ -780,6 +799,10 @@
             this.targetSdkVersion = targetSdkVersion;
         }
 
+        public boolean isGuest(ManagedServices host) {
+            return ManagedServices.this != host;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("ManagedServiceInfo[")
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 49aa73e..82c38af 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -39,6 +39,7 @@
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -96,6 +97,7 @@
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.IStatusBarNotificationHolder;
+import android.service.notification.NotificationAssistantService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -154,6 +156,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
@@ -167,11 +170,13 @@
     // message codes
     static final int MESSAGE_TIMEOUT = 2;
     static final int MESSAGE_SAVE_POLICY_FILE = 3;
-    static final int MESSAGE_RECONSIDER_RANKING = 4;
-    static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
-    static final int MESSAGE_SEND_RANKING_UPDATE = 6;
-    static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
-    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
+    static final int MESSAGE_SEND_RANKING_UPDATE = 4;
+    static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
+    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
+
+    // ranking thread messages
+    private static final int MESSAGE_RECONSIDER_RANKING = 1000;
+    private static final int MESSAGE_RANKING_SORT = 1001;
 
     static final int LONG_DELAY = 3500; // 3.5 seconds
     static final int SHORT_DELAY = 2000; // 2 seconds
@@ -281,11 +286,13 @@
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
+    private NotificationAssistant mAssistant;
     private ConditionProviders mConditionProviders;
     private NotificationUsageStats mUsageStats;
 
     private static final int MY_UID = Process.myUid();
     private static final int MY_PID = Process.myPid();
+    private RankingHandler mRankingHandler;
 
     private static class Archive {
         final int mBufferSize;
@@ -738,6 +745,7 @@
                     }
                 }
                 mListeners.onPackagesChanged(queryReplace, pkgList);
+                mAssistant.onPackagesChanged(queryReplace, pkgList);
                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
             }
@@ -779,6 +787,7 @@
                 // Refresh managed services
                 mConditionProviders.onUserSwitched(user);
                 mListeners.onUserSwitched(user);
+                mAssistant.onUserSwitched(user);
                 mZenModeHelper.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
@@ -874,8 +883,9 @@
             extractorNames = new String[0];
         }
         mUsageStats = new NotificationUsageStats(getContext());
+        mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
         mRankingHelper = new RankingHelper(getContext(),
-                new RankingWorkerHandler(mRankingThread.getLooper()),
+                mRankingHandler,
                 mUsageStats,
                 extractorNames);
         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
@@ -909,6 +919,7 @@
         importOldBlockDb();
 
         mListeners = new NotificationListeners();
+        mAssistant = new NotificationAssistant();
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
         mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
@@ -1025,6 +1036,7 @@
             // bind to listener services.
             mSettingsObserver.observe();
             mListeners.onBootPhaseAppsCanStart();
+            mAssistant.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
         }
     }
@@ -1896,6 +1908,22 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public void setImportanceFromAssistant(INotificationListener token, String key,
+                int importance, CharSequence explanation) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationList) {
+                    mAssistant.checkServiceTokenLocked(token);
+                    NotificationRecord n = mNotificationsByKey.get(key);
+                    n.setImportance(importance, explanation);
+                    mRankingHandler.requestSort();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     };
 
     private String disableNotificationEffects(NotificationRecord record) {
@@ -2037,6 +2065,8 @@
                     pw.print(listener.component);
                 }
                 pw.println(')');
+                pw.println("\n  Notification assistant:");
+                mAssistant.dump(pw, filter);
             }
             pw.println("\n  Policy access:");
             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2686,7 +2716,7 @@
         }
     }
 
-    private void handleRankingConfigChange() {
+    private void handleRankingSort() {
         synchronized (mNotificationList) {
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
@@ -2788,9 +2818,9 @@
 
     }
 
-    private final class RankingWorkerHandler extends Handler
+    private final class RankingHandlerWorker extends Handler implements RankingHandler
     {
-        public RankingWorkerHandler(Looper looper) {
+        public RankingHandlerWorker(Looper looper) {
             super(looper);
         }
 
@@ -2800,11 +2830,23 @@
                 case MESSAGE_RECONSIDER_RANKING:
                     handleRankingReconsideration(msg);
                     break;
-                case MESSAGE_RANKING_CONFIG_CHANGE:
-                    handleRankingConfigChange();
+                case MESSAGE_RANKING_SORT:
+                    handleRankingSort();
                     break;
             }
         }
+
+        public void requestSort() {
+            removeMessages(MESSAGE_RANKING_SORT);
+            sendEmptyMessage(MESSAGE_RANKING_SORT);
+        }
+
+        public void requestReconsideration(RankingReconsideration recon) {
+            Message m = Message.obtain(this,
+                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
+            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
+            sendMessageDelayed(m, delay);
+        }
     }
 
     // Notifications
@@ -3305,6 +3347,45 @@
         return true;
     }
 
+    public class NotificationAssistant extends ManagedServices {
+
+        public NotificationAssistant() {
+            super(getContext(), mHandler, mNotificationList, mUserProfiles);
+        }
+
+        @Override
+        protected Config getConfig() {
+            Config c = new Config();
+            c.caption = "notification assistant";
+            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
+            c.clientLabel = R.string.notification_assistant_binding_label;
+            return c;
+        }
+
+        @Override
+        protected IInterface asInterface(IBinder binder) {
+            return INotificationListener.Stub.asInterface(binder);
+        }
+
+        @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
+        protected void onServiceAdded(ManagedServiceInfo info) {
+            mListeners.registerGuestService(info);
+        }
+
+        @Override
+        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+            mListeners.unregisterService(removed.service, removed.userid);
+        }
+    }
+
     public class NotificationListeners extends ManagedServices {
 
         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
@@ -3332,6 +3413,11 @@
         }
 
         @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
         public void onServiceAdded(ManagedServiceInfo info) {
             final INotificationListener listener = (INotificationListener) info.service;
             final NotificationRankingUpdate update;
@@ -3366,7 +3452,6 @@
 
         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
-
         }
 
         /**
diff --git a/core/java/android/service/notification/NotificationAdjustment.aidl b/services/core/java/com/android/server/notification/RankingHandler.java
similarity index 77%
rename from core/java/android/service/notification/NotificationAdjustment.aidl
rename to services/core/java/com/android/server/notification/RankingHandler.java
index 805fe2c..80bb4f0 100644
--- a/core/java/android/service/notification/NotificationAdjustment.aidl
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.server.notification;
 
-package android.service.notification;
-
-parcelable NotificationAdjustment;
\ No newline at end of file
+public interface RankingHandler {
+    public void requestSort();
+    public void requestReconsideration(RankingReconsideration recon);
+}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3287f67..0662e7a 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.Message;
 import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -40,7 +37,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -73,10 +69,10 @@
     private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
 
     private final Context mContext;
-    private final Handler mRankingHandler;
+    private final RankingHandler mRankingHandler;
 
-    public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
-            String[] extractorNames) {
+    public RankingHelper(Context context, RankingHandler rankingHandler,
+            NotificationUsageStats usageStats, String[] extractorNames) {
         mContext = context;
         mRankingHandler = rankingHandler;
 
@@ -119,10 +115,7 @@
             try {
                 RankingReconsideration recon = extractor.process(r);
                 if (recon != null) {
-                    Message m = Message.obtain(mRankingHandler,
-                            NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
-                    long delay = recon.getDelay(TimeUnit.MILLISECONDS);
-                    mRankingHandler.sendMessageDelayed(m, delay);
+                    mRankingHandler.requestReconsideration(recon);
                 }
             } catch (Throwable t) {
                 Slog.w(TAG, "NotificationSignalExtractor failed.", t);
@@ -287,7 +280,7 @@
         for (int i = 0; i < N; i++) {
             mSignalExtractors[i].setConfig(this);
         }
-        mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
+        mRankingHandler.requestSort();
     }
 
     public void sort(ArrayList<NotificationRecord> notificationList) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7bb6d1d..a07476c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -106,6 +106,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AppsQueryHelper;
+import android.content.pm.ComponentInfo;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.EphemeralResolveInfo;
 import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
@@ -207,7 +208,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
@@ -308,7 +308,7 @@
     private static final boolean DEBUG_DEXOPT = false;
     private static final boolean DEBUG_ABI_SELECTION = false;
     private static final boolean DEBUG_EPHEMERAL = false;
-    private static final boolean DEBUG_ENCRYPTION_AWARE = false;
+    private static final boolean DEBUG_TRIAGED_MISSING = false;
 
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
@@ -2848,6 +2848,7 @@
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
         // reader
         synchronized (mPackages) {
@@ -2898,6 +2899,7 @@
     @Override
     public int getPackageUidEtc(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return -1;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
 
         // reader
@@ -2924,10 +2926,8 @@
 
     @Override
     public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) {
-            return null;
-        }
-
+        if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
                 "getPackageGids");
 
@@ -2949,8 +2949,7 @@
         return null;
     }
 
-    static PermissionInfo generatePermissionInfo(
-            BasePermission bp, int flags) {
+    static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
         if (bp.perm != null) {
             return PackageParser.generatePermissionInfo(bp.perm, flags);
         }
@@ -3068,6 +3067,7 @@
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForApplication(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
         // writer
         synchronized (mPackages) {
@@ -3182,46 +3182,88 @@
     }
 
     /**
-     * Augment the given flags depending on current user running state. This is
-     * purposefully done before acquiring {@link #mPackages} lock.
+     * Update given flags based on encryption status of current user.
      */
-    private int augmentFlagsForUser(int flags, int userId, Object cookie) {
-        if (cookie instanceof Intent) {
-            // If intent claims to be triaged, then we're fine with default
-            // matching behavior below
-            final Intent intent = (Intent) cookie;
-            if ((intent.getFlags() & Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED) != 0) {
-                flags |= PackageManager.MATCH_ENCRYPTION_DEFAULT;
-            }
-        }
-
-        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY
-                | PackageManager.MATCH_ENCRYPTION_AWARE_ONLY)) != 0) {
-            // Caller expressed an opinion about what components they want to
-            // see, so fall through and give them what they want
+    private int updateFlagsForEncryption(int flags, int userId) {
+        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
+            // Caller expressed an explicit opinion about what encryption
+            // aware/unaware components they want to see, so fall through and
+            // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
             if (isUserKeyUnlocked(userId)) {
                 flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
             } else {
-                flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
-
-                // If we have a system caller that hasn't done their homework to
-                // decide they want this default behavior, yell at them
-                if (DEBUG_ENCRYPTION_AWARE && (Binder.getCallingUid() == Process.SYSTEM_UID)
-                        && ((flags & PackageManager.MATCH_ENCRYPTION_DEFAULT) == 0)) {
-                    Log.v(TAG, "Caller hasn't been triaged for FBE; they asked about " + cookie,
-                            new Throwable());
-                }
+                flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
             }
         }
         return flags;
     }
 
+    /**
+     * Update given flags when being used to request {@link PackageInfo}.
+     */
+    private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+        boolean triaged = true;
+        if ((flags & PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+                | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS) != 0) {
+            // Caller is asking for component details, so they'd better be
+            // asking for specific encryption matching behavior, or be triaged
+            if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                    | PackageManager.MATCH_ENCRYPTION_AWARE
+                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+                triaged = false;
+            }
+        }
+        if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+                    new Throwable());
+        }
+        return updateFlagsForEncryption(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ApplicationInfo}.
+     */
+    private int updateFlagsForApplication(int flags, int userId, Object cookie) {
+        return updateFlagsForPackage(flags, userId, cookie);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ComponentInfo}.
+     */
+    private int updateFlagsForComponent(int flags, int userId, Object cookie) {
+        boolean triaged = true;
+        // Caller is asking for component details, so they'd better be
+        // asking for specific encryption matching behavior, or be triaged
+        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                | PackageManager.MATCH_ENCRYPTION_AWARE
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+                    new Throwable());
+        }
+        return updateFlagsForEncryption(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ResolveInfo}.
+     */
+    private int updateFlagsForResolve(int flags, int userId, Object cookie) {
+        return updateFlagsForComponent(flags, userId, cookie);
+    }
+
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -3266,7 +3308,7 @@
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -3285,7 +3327,7 @@
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
@@ -3304,7 +3346,7 @@
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
@@ -4429,7 +4471,7 @@
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         final ResolveInfo bestChoice =
@@ -4687,7 +4729,7 @@
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -4886,7 +4928,7 @@
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -5370,7 +5412,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
                 false, "query intent activity options");
         final String resultsAction = intent.getAction();
@@ -5543,7 +5585,7 @@
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5580,7 +5622,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
@@ -5596,7 +5638,7 @@
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5634,7 +5676,7 @@
     public List<ResolveInfo> queryIntentContentProviders(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5670,8 +5712,9 @@
 
     @Override
     public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
-
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
 
         // writer
@@ -5750,7 +5793,8 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId, permissions);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5777,7 +5821,8 @@
 
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForApplication(flags, userId, null);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5920,7 +5965,7 @@
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, name);
+        flags = updateFlagsForComponent(flags, userId, name);
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5972,7 +6017,7 @@
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, processName);
+        flags = updateFlagsForComponent(flags, userId, processName);
 
         ArrayList<ProviderInfo> finalList = null;
         // reader
@@ -6009,8 +6054,7 @@
     }
 
     @Override
-    public InstrumentationInfo getInstrumentationInfo(ComponentName name,
-            int flags) {
+    public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
         // reader
         synchronized (mPackages) {
             final PackageParser.Instrumentation i = mInstrumentation.get(name);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d2a3ede..b330139 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3846,9 +3846,9 @@
             }
         }
 
-        final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY) != 0)
+        final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE) != 0)
                 && !componentInfo.encryptionAware;
-        final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE_ONLY) != 0)
+        final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE) != 0)
                 && componentInfo.encryptionAware;
         return matchesUnaware || matchesAware;
     }
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 5948d3c..3eae7fc 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -383,13 +383,11 @@
             // Add a little delay before executing, to give the
             // dialog a chance to go away before it takes a
             // screenshot.
-            // TODO: remove once screenshots are handled by Shell (instead of dumpstate)
             mHandler.postDelayed(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        // Take a "heavy" bugreport: it's more user friendly, but causes more
-                        // interference.
+                        // Take an "interactive" bugreport.
                         ActivityManagerNative.getDefault().requestBugReport(true);
                     } catch (RemoteException e) {
                     }
@@ -405,11 +403,11 @@
                 return false;
             }
             try {
-                // Take a "light" bugreport, with less interference.
+                // Take a "full" bugreport.
                 ActivityManagerNative.getDefault().requestBugReport(false);
             } catch (RemoteException e) {
             }
-            return true;
+            return false;
         }
 
         public boolean showDuringKeyguard() {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 29e3c63..549d2dc 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -126,7 +126,7 @@
 
         final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                 resources.getString(com.android.internal.R.string.config_keyguardComponent));
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         intent.setComponent(keyguardComponent);
 
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0bbd23e..dd6493c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1322,7 +1322,7 @@
         Intent intent = new Intent();
         intent.setComponent(new ComponentName("com.android.systemui",
                     "com.android.systemui.SystemUIService"));
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         //Slog.d(TAG, "Starting service: " + intent);
         context.startServiceAsUser(intent, UserHandle.SYSTEM);
     }
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index df7b412..2640889 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -35,7 +35,7 @@
 
 public class RankingHelperTest extends AndroidTestCase {
     @Mock NotificationUsageStats mUsageStats;
-    @Mock Handler handler;
+    @Mock RankingHandler handler;
 
     private Notification mNotiGroupGSortA;
     private Notification mNotiGroupGSortB;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 92d5aa9..5d5df95 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -269,7 +269,7 @@
          * @return Whether the specified capability is supported.
          */
         public static boolean can(int capabilities, int capability) {
-            return (capabilities & capability) != 0;
+            return (capabilities & capability) == capability;
         }
 
         /**
@@ -351,7 +351,7 @@
          * @return Whether the specified property is supported.
          */
         public static boolean hasProperty(int properties, int property) {
-            return (properties & property) != 0;
+            return (properties & property) == property;
         }
 
         /**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 17bd08c..deb98f4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -294,7 +294,7 @@
      * @hide
      */
     public static boolean can(int capabilities, int capability) {
-        return (capabilities & capability) != 0;
+        return (capabilities & capability) == capability;
     }
 
     /**
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 27ee804..a915d37 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -155,8 +155,7 @@
 
         // Get the list of apps registered for the DIAL intent with empty scheme
         Intent intent = new Intent(Intent.ACTION_DIAL);
-        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent,
-                PackageManager.MATCH_ENCRYPTION_DEFAULT);
+        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
 
         List<String> packageNames = new ArrayList<>();
 
@@ -209,7 +208,7 @@
 
         final List<String> result = new ArrayList<>();
         final List<ResolveInfo> resolveInfoList = context.getPackageManager()
-                .queryIntentActivities(intent, PackageManager.MATCH_ENCRYPTION_DEFAULT);
+                .queryIntentActivities(intent, 0);
         final int length = resolveInfoList.size();
         for (int i = 0; i < length; i++) {
             final ActivityInfo info = resolveInfoList.get(i).activityInfo;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8537f9c..c680999 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -153,6 +153,17 @@
      * @hide
      */
     public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+
+    /** @hide */
+    public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
+            (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_IS95B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_1xRTT - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_0 - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1));
+
     /**
      * Available registration states for GSM, UMTS and CDMA.
      */
@@ -1141,16 +1152,8 @@
     }
 
     /** @hide */
-    public static boolean hasCdma(int radioTechnologyBitmask) {
-        int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
-                | RIL_RADIO_TECHNOLOGY_IS95B
-                | RIL_RADIO_TECHNOLOGY_1xRTT
-                | RIL_RADIO_TECHNOLOGY_EVDO_0
-                | RIL_RADIO_TECHNOLOGY_EVDO_A
-                | RIL_RADIO_TECHNOLOGY_EVDO_B
-                | RIL_RADIO_TECHNOLOGY_EHRPD);
-
-        return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+    public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
+        return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
     }
 
     /** @hide */