Merge "New behavior for docked stack when going home" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 2b1c42e..3240467 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4880,7 +4880,6 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public android.app.Notification.Topic getTopic();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4944,7 +4943,6 @@
     field public static final int PRIORITY_MAX = 2; // 0x2
     field public static final int PRIORITY_MIN = -2; // 0xfffffffe
     field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
-    field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
     field public static final int VISIBILITY_PRIVATE = 0; // 0x0
     field public static final int VISIBILITY_PUBLIC = 1; // 0x1
     field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5096,7 +5094,6 @@
     method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
     method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
     method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
-    method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
     method public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
@@ -5164,16 +5161,6 @@
     field protected android.app.Notification.Builder mBuilder;
   }
 
-  public static class Notification.Topic implements android.os.Parcelable {
-    ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
-    method public android.app.Notification.Topic clone();
-    method public int describeContents();
-    method public java.lang.String getId();
-    method public java.lang.CharSequence getLabel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
-  }
-
   public static final class Notification.WearableExtender implements android.app.Notification.Extender {
     ctor public Notification.WearableExtender();
     ctor public Notification.WearableExtender(android.app.Notification);
@@ -5236,7 +5223,7 @@
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
-    method public int getImportance(java.lang.String);
+    method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -34592,6 +34579,7 @@
     method public final void startActivityAndCollapse(android.content.Intent);
     method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 2e9e08f..7dde390 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5012,7 +5012,6 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public android.app.Notification.Topic getTopic();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -5076,7 +5075,6 @@
     field public static final int PRIORITY_MAX = 2; // 0x2
     field public static final int PRIORITY_MIN = -2; // 0xfffffffe
     field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
-    field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
     field public static final int VISIBILITY_PRIVATE = 0; // 0x0
     field public static final int VISIBILITY_PUBLIC = 1; // 0x1
     field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5228,7 +5226,6 @@
     method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
     method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
     method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
-    method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
     method public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
@@ -5296,16 +5293,6 @@
     field protected android.app.Notification.Builder mBuilder;
   }
 
-  public static class Notification.Topic implements android.os.Parcelable {
-    ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
-    method public android.app.Notification.Topic clone();
-    method public int describeContents();
-    method public java.lang.String getId();
-    method public java.lang.CharSequence getLabel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
-  }
-
   public static final class Notification.WearableExtender implements android.app.Notification.Extender {
     ctor public Notification.WearableExtender();
     ctor public Notification.WearableExtender(android.app.Notification);
@@ -5368,7 +5355,7 @@
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
-    method public int getImportance(java.lang.String);
+    method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -36984,9 +36971,8 @@
     field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
     field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
     field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
-    field public static final int REASON_PACKAGE_SUSPENDED = 15; // 0xf
-    field public static final int REASON_PROFILE_TURNED_OFF = 16; // 0x10
-    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
+    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
     field public static final int REASON_USER_STOPPED = 6; // 0x6
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
@@ -37148,6 +37134,7 @@
     method public final void startActivityAndCollapse(android.content.Intent);
     method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 550d6df..287f785 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4880,7 +4880,6 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public android.app.Notification.Topic getTopic();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4944,7 +4943,6 @@
     field public static final int PRIORITY_MAX = 2; // 0x2
     field public static final int PRIORITY_MIN = -2; // 0xfffffffe
     field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
-    field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
     field public static final int VISIBILITY_PRIVATE = 0; // 0x0
     field public static final int VISIBILITY_PUBLIC = 1; // 0x1
     field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5096,7 +5094,6 @@
     method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
     method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
     method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
-    method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
     method public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
@@ -5164,16 +5161,6 @@
     field protected android.app.Notification.Builder mBuilder;
   }
 
-  public static class Notification.Topic implements android.os.Parcelable {
-    ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
-    method public android.app.Notification.Topic clone();
-    method public int describeContents();
-    method public java.lang.String getId();
-    method public java.lang.CharSequence getLabel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
-  }
-
   public static final class Notification.WearableExtender implements android.app.Notification.Extender {
     ctor public Notification.WearableExtender();
     ctor public Notification.WearableExtender(android.app.Notification);
@@ -5236,7 +5223,7 @@
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
-    method public int getImportance(java.lang.String);
+    method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -34607,6 +34594,7 @@
     method public final void startActivityAndCollapse(android.content.Intent);
     method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
     field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3c8dfce..8be00aa 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,16 +48,13 @@
     boolean areNotificationsEnabledForPackage(String pkg, int uid);
     boolean areNotificationsEnabled(String pkg);
 
-    ParceledListSlice getTopics(String pkg, int uid);
-    void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
-    int getVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
-    void setPriority(String pkg, int uid, in Notification.Topic topic, int priority);
-    int getPriority(String pkg, int uid, in Notification.Topic topic);
-    void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
-    int getImportance(String pkg, int uid, in Notification.Topic topic);
-    int getTopicImportance(String pkg, String topicId);
-    boolean doesUserUseTopics(String pkg, int uid);
-    boolean hasBannedTopics(String pkg, int uid);
+    void setVisibilityOverride(String pkg, int uid, int visibility);
+    int getVisibilityOverride(String pkg, int uid);
+    void setPriority(String pkg, int uid, int priority);
+    int getPriority(String pkg, int uid);
+    void setImportance(String pkg, int uid, int importance);
+    int getImportance(String pkg, int uid);
+    int getPackageImportance(String pkg);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 52631d1..13b5b5c8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1366,98 +1366,6 @@
     public Notification publicVersion;
 
     /**
-     * Structure to encapsulate a topic that is shown in Notification settings.
-     * It must include an id and label.
-     */
-    public static class Topic implements Parcelable {
-        private final String id;
-        private final CharSequence label;
-
-        public Topic(String id, CharSequence label) {
-            this.id = id;
-            this.label = safeCharSequence(label);
-        }
-
-        private Topic(Parcel in) {
-            if (in.readInt() != 0) {
-                id = in.readString();
-            } else {
-                id = null;
-            }
-            label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        }
-
-        public String getId() {
-            return id;
-        }
-
-        public CharSequence getLabel() {
-            return label;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder(Topic.class.getSimpleName()).append('[')
-                    .append("id=").append(id)
-                    .append(",label=").append(label)
-                    .append(']').toString();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof Topic)) return false;
-            if (o == this) return true;
-            final Topic other = (Topic) o;
-            return Objects.equals(other.id, id)
-                    && Objects.equals(other.label, label);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(id, label);
-        }
-
-        @Override
-        public Topic clone() {
-            return new Topic(id, label);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            if (id != null) {
-                out.writeInt(1);
-                out.writeString(id);
-            } else {
-                out.writeInt(0);
-            }
-            TextUtils.writeToParcel(label, out, flags);
-        }
-        public static final Parcelable.Creator<Topic> CREATOR =
-                new Parcelable.Creator<Topic>() {
-                    public Topic createFromParcel(Parcel in) {
-                        return new Topic(in);
-                    }
-                    public Topic[] newArray(int size) {
-                        return new Topic[size];
-                    }
-                };
-    }
-
-    @SystemApi
-    public static final String TOPIC_DEFAULT = "system_default_topic";
-
-    private Topic topic;
-
-    public Topic getTopic() {
-        return topic;
-    }
-
-    /**
      * Constructs a Notification object with default values.
      * You might want to consider using {@link Builder} instead.
      */
@@ -1583,10 +1491,6 @@
         }
 
         color = parcel.readInt();
-
-        if (parcel.readInt() != 0) {
-            topic = Topic.CREATOR.createFromParcel(parcel);
-        }
     }
 
     @Override
@@ -1687,10 +1591,6 @@
 
         that.color = this.color;
 
-        if (this.topic != null) {
-            that.topic = this.topic.clone();
-        }
-
         if (!heavy) {
             that.lightenPayload(); // will clean out extras
         }
@@ -1871,13 +1771,6 @@
         }
 
         parcel.writeInt(color);
-
-        if (topic != null) {
-            parcel.writeInt(1);
-            topic.writeToParcel(parcel, 0);
-        } else {
-            parcel.writeInt(0);
-        }
     }
 
     /**
@@ -2020,10 +1913,6 @@
             sb.append(" publicVersion=");
             sb.append(publicVersion.toString());
         }
-        if (topic != null) {
-            sb.append("topic=");
-            sb.append(topic.toString());
-        }
         sb.append(")");
         return sb.toString();
     }
@@ -2995,19 +2884,6 @@
             return this;
         }
 
-        /**
-         * Sets the topic of this notification. Topics are typically displayed in Notification
-         * settings.
-         * <p>
-         * Every topic must have an id and a textual label.
-         *
-         * @param topic The topic to add.
-         */
-        public Builder setTopic(Topic topic) {
-            mN.topic = topic;
-            return this;
-        }
-
         private Drawable getProfileBadgeDrawable() {
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ff2cfd6..324a0ab 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -507,11 +507,10 @@
         return false;
     }
 
-    public int getImportance(String topicId) {
-        Preconditions.checkNotNull(topicId);
+    public int getImportance() {
         INotificationManager service = getService();
         try {
-            return service.getTopicImportance(mContext.getPackageName(), topicId);
+            return service.getPackageImportance(mContext.getPackageName());
         } catch (RemoteException e) {
         }
         return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b33e807..a738b2e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2827,7 +2827,7 @@
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
         dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA, wifiOnTime / 1000,
-                wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+                wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0);
 
         dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_WIFI_CONTROLLER_DATA,
                 getWifiControllerActivity(), which);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7ba48b9..512ac92 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -114,6 +114,21 @@
             "android.settings.LOCATION_SOURCE_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of users.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_USER_SETTINGS =
+            "android.settings.USER_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of wireless controls
      * such as Wi-Fi, Bluetooth and Mobile networks.
      * <p>
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index fb58f4e..b5387f1 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -97,14 +97,11 @@
     /** Notification was canceled because it was an invisible member of a group. */
     public static final int REASON_GROUP_OPTIMIZATION = 13;
 
-    /** Notification was canceled by the user banning the topic. */
-    public static final int REASON_TOPIC_BANNED = 14;
-
     /** Notification was canceled by the device administrator suspending the package. */
-    public static final int REASON_PACKAGE_SUSPENDED = 15;
+    public static final int REASON_PACKAGE_SUSPENDED = 14;
 
     /** Notification was canceled by the owning managed profile being turned off. */
-    public static final int REASON_PROFILE_TURNED_OFF = 16;
+    public static final int REASON_PROFILE_TURNED_OFF = 15;
 
     public class Adjustment {
         int mImportance;
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 0cf1175..553d539 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -16,6 +16,8 @@
 package android.service.quicksettings;
 
 import android.Manifest;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.app.Dialog;
 import android.app.Service;
@@ -74,6 +76,14 @@
 public class TileService extends Service {
 
     /**
+     * An activity that provides a user interface for adjusting TileService preferences.
+     * Optional but recommended for apps that implement a TileService.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String ACTION_QS_TILE_PREFERENCES
+            = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+
+    /**
      * 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/res/res/values/config.xml b/core/res/res/values/config.xml
index 016ed60..3a185d6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1992,10 +1992,10 @@
      See {@link com.android.server.notification.NotificationSignalExtractor} -->
     <string-array name="config_notificationSignalExtractors">
         <item>com.android.server.notification.ValidateNotificationPeople</item>
-        <item>com.android.server.notification.TopicPriorityExtractor</item>
-        <item>com.android.server.notification.TopicImportanceExtractor</item>
+        <item>com.android.server.notification.PriorityExtractor</item>
+        <item>com.android.server.notification.ImportanceExtractor</item>
         <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
-        <item>com.android.server.notification.TopicVisibilityExtractor</item>
+        <item>com.android.server.notification.VisibilityExtractor</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1f0e96d..da88146 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4162,9 +4162,7 @@
         <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
     </plurals>
 
-    <string name="default_notification_topic_label">Miscellaneous</string>
-
-    <string name="importance_from_topic">You set the importance of these notifications.</string>
+    <string name="importance_from_user">You set the importance of these notifications.</string>
     <string name="importance_from_person">This is important because of the people involved.</string>
 
     <!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fc9f7a4..719e554 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2389,7 +2389,6 @@
   <java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
 
   <java-symbol type="string" name="config_packagedKeyboardName" />
-  <java-symbol type="string" name="default_notification_topic_label" />
   <java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
@@ -2428,7 +2427,7 @@
   <java-symbol type="dimen" name="notification_content_margin_end" />
   <java-symbol type="dimen" name="notification_content_picture_margin" />
   <java-symbol type="dimen" name="notification_content_margin_top" />
-  <java-symbol type="string" name="importance_from_topic" />
+  <java-symbol type="string" name="importance_from_user" />
   <java-symbol type="string" name="importance_from_person" />
 
   <java-symbol type="layout" name="work_widget_mask_view" />
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6257122..8660b75 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -7,7 +7,7 @@
 # Enables fine-grained GLES error checking
 # If set to true, every GLES call is wrapped & error checked
 # Has moderate overhead
-HWUI_ENABLE_OPENGL_VALIDATION := false
+HWUI_ENABLE_OPENGL_VALIDATION := true
 
 hwui_src_files := \
     font/CacheTexture.cpp \
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index fd96391..216509d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -18,6 +18,7 @@
 
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.internal.util.Preconditions.checkState;
 
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -40,6 +41,7 @@
 
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
@@ -85,15 +87,13 @@
 
         // Create a new anonymous "Recents" RootInfo. It's a faker.
         mRecentsRoot = new RootInfo() {{
-            // Special root for recents
-            authority = null;
-            rootId = null;
-            derivedIcon = R.drawable.ic_root_recent;
-            derivedType = RootInfo.TYPE_RECENTS;
-            flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
-            title = mContext.getString(R.string.root_recent);
-            availableBytes = -1;
-        }};
+                // Special root for recents
+                derivedIcon = R.drawable.ic_root_recent;
+                derivedType = RootInfo.TYPE_RECENTS;
+                flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
+                title = mContext.getString(R.string.root_recent);
+                availableBytes = -1;
+            }};
     }
 
     private class RootsChangedObserver extends ContentObserver {
@@ -116,6 +116,16 @@
      * Gather roots from all known storage providers.
      */
     public void updateAsync() {
+        // Verifying an assumption about the recents root being immutable.
+        if (DEBUG) {
+            checkState(mRecentsRoot.authority == null);
+            checkState(mRecentsRoot.rootId == null);
+            checkState(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
+            checkState(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
+            checkState(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD));
+            checkState(mRecentsRoot.title == mContext.getString(R.string.root_recent));
+            checkState(mRecentsRoot.availableBytes == -1);
+        }
         new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
@@ -412,9 +422,10 @@
             if (!state.showAdvanced && root.isAdvanced()) continue;
             // Exclude non-local devices when local only
             if (state.localOnly && !root.isLocalOnly()) continue;
-            // Exclude downloads roots that don't support directory creation
-            // TODO: Add flag to check the root supports directory creation or not.
-            if (state.directoryCopy && !root.supportsChildren()) continue;
+            // Exclude downloads roots as it doesn't support directory creation (actually
+            // we just don't show them).
+            // TODO: Add flag to check the root supports directory creation.
+            if (state.directoryCopy && !root.isDownloads()) continue;
 
             // Only show empty roots when creating, or in browse mode.
             if (root.isEmpty() && (state.action == State.ACTION_OPEN
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index f908eeb..9f83c04 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -45,7 +45,6 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 
 import java.util.ArrayList;
@@ -403,17 +402,7 @@
     public static class RootComparator implements Comparator<RootItem> {
         @Override
         public int compare(RootItem lhs, RootItem rhs) {
-            // Sort by root type, then title, then summary.
-            int score = lhs.root.derivedType - rhs.root.derivedType;
-            if (score != 0) {
-                return score;
-            }
-            score = DocumentInfo.compareToIgnoreCaseNullable(lhs.root.title, rhs.root.title);
-            if (score != 0) {
-                return score;
-            }
-
-            return DocumentInfo.compareToIgnoreCaseNullable(lhs.root.summary, rhs.root.summary);
+            return lhs.root.compareTo(rhs.root);
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 22cb25a2..b90a119 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,14 +17,17 @@
 package com.android.documentsui;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.Time;
 
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.List;
 
 /** @hide */
 public final class Shared {
+
     /** Intent action name to pick a copy destination. */
     public static final String ACTION_PICK_COPY_DESTINATION =
             "com.android.documentsui.PICK_COPY_DESTINATION";
@@ -39,6 +42,19 @@
     public static final String TAG = "Documents";
     public static final String EXTRA_STACK = "com.android.documentsui.STACK";
 
+
+    /**
+     * String prefix used to indicate the document is a directory.
+     */
+    public static final char DIR_PREFIX = '\001';
+
+    private static final Collator sCollator;
+
+    static {
+        sCollator = Collator.getInstance();
+        sCollator.setStrength(Collator.SECONDARY);
+    }
+
     /**
      * Generates a formatted quantity string.
      */
@@ -76,4 +92,26 @@
             ? (ArrayList<T>) list
             : new ArrayList<T>(list);
     }
+
+    /**
+     * Compare two strings against each other using system default collator in a
+     * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX}
+     * before other items.
+     */
+    public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
+        final boolean leftEmpty = TextUtils.isEmpty(lhs);
+        final boolean rightEmpty = TextUtils.isEmpty(rhs);
+
+        if (leftEmpty && rightEmpty) return 0;
+        if (leftEmpty) return -1;
+        if (rightEmpty) return 1;
+
+        final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
+        final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
+
+        if (leftDir && !rightDir) return -1;
+        if (rightDir && !leftDir) return 1;
+
+        return sCollator.compare(lhs, rhs);
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 0a9789f..4583dec 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1071,8 +1071,8 @@
             return false;
         }
 
-        // Can't copy folders to roots that don't support children.
-        if (!root.supportsChildren()) {
+        // Can't copy folders to downloads, because we don't show folders there.
+        if (!root.isDownloads()) {
             for (DocumentInfo docs : files) {
                 if (docs.isDirectory()) {
                     return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index b369448..9684a5a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -35,6 +35,7 @@
 
 import com.android.documentsui.DirectoryResult;
 import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
 import com.android.documentsui.model.DocumentInfo;
 
@@ -170,7 +171,7 @@
                     final String displayName = getCursorString(
                             mCursor, Document.COLUMN_DISPLAY_NAME);
                     if (Document.MIME_TYPE_DIR.equals(mimeType)) {
-                        stringValues[pos] = DocumentInfo.DIR_PREFIX + displayName;
+                        stringValues[pos] = Shared.DIR_PREFIX + displayName;
                     } else {
                         stringValues[pos] = displayName;
                     }
@@ -227,7 +228,7 @@
 
                 final String lhs = pivotValue;
                 final String rhs = sortKey[mid];
-                final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
+                final int compare = Shared.compareToIgnoreCaseNullable(lhs, rhs);
 
                 if (compare < 0) {
                     right = mid;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 1c696ad..e9fdab0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -26,7 +26,6 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsProvider;
 import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
 
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.RootCursorWrapper;
@@ -38,7 +37,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.ProtocolException;
-import java.text.Collator;
 import java.util.Objects;
 
 /**
@@ -48,13 +46,6 @@
     private static final int VERSION_INIT = 1;
     private static final int VERSION_SPLIT_URI = 2;
 
-    private static final Collator sCollator;
-
-    static {
-        sCollator = Collator.getInstance();
-        sCollator.setStrength(Collator.SECONDARY);
-    }
-
     public String authority;
     public String documentId;
     public String mimeType;
@@ -320,31 +311,4 @@
         fnfe.initCause(t);
         throw fnfe;
     }
-
-    /**
-     * String prefix used to indicate the document is a directory.
-     */
-    public static final char DIR_PREFIX = '\001';
-
-    /**
-     * Compare two strings against each other using system default collator in a
-     * case-insensitive mode. Clusters strings prefixed with {@link #DIR_PREFIX}
-     * before other items.
-     */
-    public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
-        final boolean leftEmpty = TextUtils.isEmpty(lhs);
-        final boolean rightEmpty = TextUtils.isEmpty(rhs);
-
-        if (leftEmpty && rightEmpty) return 0;
-        if (leftEmpty) return -1;
-        if (rightEmpty) return 1;
-
-        final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
-        final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
-
-        if (leftDir && !rightDir) return -1;
-        if (rightDir && !leftDir) return 1;
-
-        return sCollator.compare(lhs, rhs);
-    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3f4a1df..3897058 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -16,10 +16,12 @@
 
 package com.android.documentsui.model;
 
+import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
@@ -36,17 +38,31 @@
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.ProtocolException;
 import java.util.Objects;
 
 /**
  * Representation of a {@link Root}.
  */
-public class RootInfo implements Durable, Parcelable {
+public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
     private static final int VERSION_INIT = 1;
     private static final int VERSION_DROP_TYPE = 2;
 
     // The values of these constants determine the sort order of various roots in the RootsFragment.
+    @IntDef(flag = true, value = {
+            TYPE_IMAGES,
+            TYPE_VIDEO,
+            TYPE_AUDIO,
+            TYPE_RECENTS,
+            TYPE_DOWNLOADS,
+            TYPE_LOCAL,
+            TYPE_MTP,
+            TYPE_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RootType {}
     public static final int TYPE_IMAGES = 1;
     public static final int TYPE_VIDEO = 2;
     public static final int TYPE_AUDIO = 3;
@@ -69,7 +85,7 @@
     /** Derived fields that aren't persisted */
     public String[] derivedMimeTypes;
     public int derivedIcon;
-    public int derivedType;
+    public @RootType int derivedType;
 
     public RootInfo() {
         reset();
@@ -329,6 +345,22 @@
     }
 
     @Override
+    public int compareTo(RootInfo other) {
+        // Sort by root type, then title, then summary.
+        int score = derivedType - other.derivedType;
+        if (score != 0) {
+            return score;
+        }
+
+        score = compareToIgnoreCaseNullable(title, other.title);
+        if (score != 0) {
+            return score;
+        }
+
+        return compareToIgnoreCaseNullable(summary, other.summary);
+    }
+
+    @Override
     public String toString() {
         return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 83299f0..4b0bc41 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -28,6 +28,7 @@
 
 import com.android.documentsui.DirectoryResult;
 import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
 import com.android.documentsui.State;
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
 import com.android.documentsui.model.DocumentInfo;
@@ -190,7 +191,7 @@
 
         assertEquals(ITEM_COUNT, seen.cardinality());
         for (int i = 0; i < names.size()-1; ++i) {
-            assertTrue(DocumentInfo.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
+            assertTrue(Shared.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index c44b638..6d29c5f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -113,6 +113,12 @@
         return admin;
     }
 
+    public static boolean hasBaseUserRestriction(Context context,
+            String userRestriction, int userId) {
+        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
+    }
+
     /**
      * Checks if keyguard features are disabled by policy.
      *
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 9bd4eb1..227b1e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -70,6 +70,12 @@
                 }
             }
             mAttrUserRestriction = data == null ? null : data.toString();
+            // If the system has set the user restriction, then we shouldn't add the padlock.
+            if (RestrictedLockUtils.hasBaseUserRestriction(mContext, mAttrUserRestriction,
+                    UserHandle.myUserId())) {
+                mAttrUserRestriction = null;
+                return;
+            }
 
             final TypedValue useAdminDisabledSummary =
                     attributes.peekValue(R.styleable.RestrictedPreference_useAdminDisabledSummary);
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index e550d9c..4d0eb96 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -126,27 +126,6 @@
                     android:tint="@color/notification_guts_icon_tint" />
 
         </FrameLayout>
-
-        <RadioGroup
-                    android:id="@+id/apply_to"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" >
-            <RadioButton android:id="@+id/apply_to_topic"
-                         android:layout_width="wrap_content"
-                         android:layout_height="48dp"
-                         style="@style/TextAppearance.NotificationGuts.Primary"
-                         android:visibility="gone"
-                         android:buttonTint="#858383"
-            />
-            <RadioButton android:id="@+id/apply_to_app"
-                         android:layout_width="wrap_content"
-                         android:layout_height="48dp"
-                         android:text="@string/apply_to_app"
-                         style="@style/TextAppearance.NotificationGuts.Primary"
-                         android:visibility="gone"
-                         android:buttonTint="#858383"
-            />
-        </RadioGroup>
     </LinearLayout>
     <!-- buttons -->
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
new file mode 100644
index 0000000..74f6f9d
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2016, 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.
+-->
+<com.android.systemui.statusbar.NotificationSettingsIconRow
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    >
+
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:id="@+id/gear_icon"
+        android:layout_width="@dimen/notification_gear_size"
+        android:layout_height="@dimen/notification_gear_size"
+        android:layout_marginTop="@dimen/notification_gear_top_margin"
+        android:layout_marginStart="@dimen/notification_gear_side_margin"
+        android:layout_marginEnd="@dimen/notification_gear_side_margin"
+        android:src="@drawable/ic_settings"
+        android:tint="@color/notification_gear_color"
+        android:visibility="gone"
+        android:alpha="0"
+        android:background="?android:attr/selectableItemBackgroundBorderless"
+        />
+
+</com.android.systemui.statusbar.NotificationSettingsIconRow>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 62fdd42..045ede3 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -23,6 +23,14 @@
     android:clickable="true"
     >
 
+    <ViewStub
+        android:layout="@layout/notification_settings_icon_row"
+        android:id="@+id/settings_icon_row_stub"
+        android:inflatedId="@+id/notification_settings_icon_row"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+
     <com.android.systemui.statusbar.NotificationBackgroundView
         android:id="@+id/backgroundNormal"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4cd920a..8f69bbb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -102,6 +102,9 @@
     <!-- The color of the circle around the primary user in the user switcher -->
     <color name="current_user_border_color">@color/system_accent_color</color>
 
+    <!-- The color of the gear shown behind a notification -->
+    <color name="notification_gear_color">#ff757575</color>
+
     <!-- The "inside" of a notification, reached via longpress -->
     <color name="notification_guts_bg_color">#eeeeee</color>
     <color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b8044ba..8c93e2a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -78,6 +78,15 @@
     <!-- Minimum layouted height of a notification in the statusbar-->
     <dimen name="min_notification_layout_height">48dp</dimen>
 
+    <!-- Size of gear icon displayed behind a notification -->
+    <dimen name="notification_gear_size">24dp</dimen>
+
+    <!-- The space above the gear icon displayed behind a notification -->
+    <dimen name="notification_gear_top_margin">30dp</dimen>
+
+    <!-- The space on either side of the gear icon displayed behind a notification  -->
+    <dimen name="notification_gear_side_margin">20dp</dimen>
+
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">17dip</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33b43fe..33f3c30 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -69,9 +69,9 @@
     private float mPerpendicularInitialTouchPos;
     private boolean mDragging;
     private View mCurrView;
-    private View mCurrAnimView;
     private boolean mCanCurrViewBeDimissed;
     private float mDensityScale;
+    private float mTranslation = 0;
 
     private boolean mLongPressSent;
     private LongPressListener mLongPressListener;
@@ -121,7 +121,7 @@
         return mSwipeDirection == X ? ev.getY() : ev.getX();
     }
 
-    private float getTranslation(View v) {
+    protected float getTranslation(View v) {
         return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
     }
 
@@ -130,7 +130,7 @@
                 vt.getYVelocity();
     }
 
-    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
+    protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
         ObjectAnimator anim = ObjectAnimator.ofFloat(v,
                 mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
         return anim;
@@ -141,7 +141,17 @@
                 vt.getXVelocity();
     }
 
-    private void setTranslation(View v, float translate) {
+    protected Animator getViewTranslationAnimator(View v, float target,
+            AnimatorUpdateListener listener) {
+        ObjectAnimator anim = createTranslationAnimation(v, target);
+        anim.addUpdateListener(listener);
+        return anim;
+    }
+
+    protected void setTranslation(View v, float translate) {
+        if (v == null) {
+            return;
+        }
         if (mSwipeDirection == X) {
             v.setTranslationX(translate);
         } else {
@@ -237,15 +247,16 @@
                 mTouchAboveFalsingThreshold = false;
                 mDragging = false;
                 mLongPressSent = false;
-                mCurrView = mCallback.getChildAtPosition(ev);
                 mVelocityTracker.clear();
+                mCurrView = mCallback.getChildAtPosition(ev);
+
                 if (mCurrView != null) {
-                    mCurrAnimView = mCallback.getChildContentView(mCurrView);
+                    onDownUpdate(mCurrView);
                     mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
                     mVelocityTracker.addMovement(ev);
                     mInitialTouchPos = getPos(ev);
                     mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
-
+                    mTranslation = getTranslation(mCurrView);
                     if (mLongPressListener != null) {
                         if (mWatchLongPress == null) {
                             mWatchLongPress = new Runnable() {
@@ -268,7 +279,6 @@
                         }
                         mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
                     }
-
                 }
                 break;
 
@@ -283,8 +293,8 @@
                             && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
                         mCallback.onBeginDrag(mCurrView);
                         mDragging = true;
-                        mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
-
+                        mInitialTouchPos = getPos(ev);
+                        mTranslation = getTranslation(mCurrView);
                         removeLongPressCallback();
                     }
                 }
@@ -295,7 +305,6 @@
                 final boolean captured = (mDragging || mLongPressSent);
                 mDragging = false;
                 mCurrView = null;
-                mCurrAnimView = null;
                 mLongPressSent = false;
                 removeLongPressCallback();
                 if (captured) return true;
@@ -320,12 +329,11 @@
      * @param useAccelerateInterpolator Should an accelerating Interpolator be used
      * @param fixedDuration If not 0, this exact duration will be taken
      */
-    public void dismissChild(final View view, float velocity, final Runnable endAction,
+    public void dismissChild(final View animView, float velocity, final Runnable endAction,
             long delay, boolean useAccelerateInterpolator, long fixedDuration) {
-        final View animView = mCallback.getChildContentView(view);
-        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
+        final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
         float newPos;
-        boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
 
         if (velocity < 0
                 || (velocity == 0 && getTranslation(animView) < 0)
@@ -355,7 +363,13 @@
         if (!mDisableHwLayers) {
             animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         }
-        ObjectAnimator anim = createTranslationAnimation(animView, newPos);
+        AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
+            }
+        };
+
+        Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
         if (useAccelerateInterpolator) {
             anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
         } else {
@@ -367,8 +381,8 @@
         }
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animation) {
-                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
-                mCallback.onChildDismissed(view);
+                updateSwipeProgressFromOffset(animView, canBeDismissed);
+                mCallback.onChildDismissed(animView);
                 if (endAction != null) {
                     endAction.run();
                 }
@@ -377,11 +391,6 @@
                 }
             }
         });
-        anim.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
-            }
-        });
         prepareDismissAnimation(animView, anim);
         anim.start();
     }
@@ -393,21 +402,21 @@
         // Do nothing
     }
 
-    public void snapChild(final View view, float velocity) {
-        final View animView = mCallback.getChildContentView(view);
-        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
-        ObjectAnimator anim = createTranslationAnimation(animView, 0);
+    public void snapChild(final View animView, final float targetLeft, float velocity) {
+        final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
+        AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
+            }
+        };
+
+        Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
-        anim.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
-            }
-        });
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animator) {
-                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
-                mCallback.onChildSnappedBack(animView);
+                updateSwipeProgressFromOffset(animView, canBeDismissed);
+                mCallback.onChildSnappedBack(animView, targetLeft);
             }
         });
         prepareSnapBackAnimation(animView, anim);
@@ -421,6 +430,28 @@
         // Do nothing
     }
 
+    /**
+     * Called when there's a down event.
+     */
+    public void onDownUpdate(View currView) {
+        // Do nothing
+    }
+
+    /**
+     * Called on a move event.
+     */
+    protected void onMoveUpdate(View view, float totalTranslation, float delta) {
+        // Do nothing
+    }
+
+    /**
+     * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
+     * view is being animated to dismiss or snap.
+     */
+    public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+        updateSwipeProgressFromOffset(animView, canBeDismissed);
+    }
+
     public boolean onTouchEvent(MotionEvent ev) {
         if (mLongPressSent) {
             return true;
@@ -456,17 +487,18 @@
                     // don't let items that can't be dismissed be dragged more than
                     // maxScrollDistance
                     if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
-                        float size = getSize(mCurrAnimView);
-                        float maxScrollDistance = 0.15f * size;
+                        float size = getSize(mCurrView);
+                        float maxScrollDistance = 0.25f * size;
                         if (absDelta >= size) {
                             delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
                         } else {
                             delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
                         }
                     }
-                    setTranslation(mCurrAnimView, delta);
 
-                    updateSwipeProgressFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
+                    setTranslation(mCurrView, mTranslation + delta);
+                    updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
+                    onMoveUpdate(mCurrView, mTranslation + delta, delta);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -478,12 +510,13 @@
                     float velocity = getVelocity(mVelocityTracker);
                     float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
 
+                    float translation = getTranslation(mCurrView);
                     // Decide whether to dismiss the current view
                     boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
-                            Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
+                            Math.abs(translation) > 0.4 * getSize(mCurrView);
                     boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
                             (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
-                            (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
+                            (velocity > 0) == (translation > 0);
                     boolean falsingDetected = mCallback.isAntiFalsingNeeded();
 
                     if (mFalsingManager.isClassiferEnabled()) {
@@ -502,7 +535,7 @@
                     } else {
                         // snappity
                         mCallback.onDragCancelled(mCurrView);
-                        snapChild(mCurrView, velocity);
+                        snapChild(mCurrView, 0 /* leftTarget */, velocity);
                     }
                 }
                 break;
@@ -518,8 +551,6 @@
     public interface Callback {
         View getChildAtPosition(MotionEvent ev);
 
-        View getChildContentView(View v);
-
         boolean canChildBeDismissed(View v);
 
         boolean isAntiFalsingNeeded();
@@ -530,7 +561,13 @@
 
         void onDragCancelled(View v);
 
-        void onChildSnappedBack(View animView);
+        /**
+         * Called when the child is snapped to a position.
+         *
+         * @param animView the view that was snapped.
+         * @param targetLeft the left position the view was snapped to.
+         */
+        void onChildSnappedBack(View animView, float targetLeft);
 
         /**
          * Updates the swipe progress on a child.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 53abe37..5e653dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -329,7 +329,8 @@
         final View.OnLongClickListener longClick = new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                return false;
+                r.tile.longClick();
+                return true;
             }
         };
         r.tileView.init(click, longClick);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 6b94195..f02424b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -212,9 +212,11 @@
     }
 
     protected void handleLongClick() {
-        // optional
+        mHost.startActivityDismissingKeyguard(getLongClickIntent());
     }
 
+    public abstract Intent getLongClickIntent();
+
     protected void handleClearState() {
         mTmpState = newTileState();
         mState = newTileState();
@@ -279,10 +281,11 @@
         mCallbacks.clear();
     }
 
-    protected void checkIfRestrictionEnforced(State state, String userRestriction) {
+    protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
         EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
                 userRestriction, ActivityManager.getCurrentUser());
-        if (admin != null) {
+        if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+                userRestriction, ActivityManager.getCurrentUser())) {
             state.disabledByPolicy = true;
             state.enforcedAdmin = admin;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 1a854c2..f74117c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -77,6 +77,7 @@
     public void init(OnClickListener click, OnLongClickListener longClick) {
         setClickable(true);
         setOnClickListener(click);
+        setOnLongClickListener(longClick);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 0d5d115..523792b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -84,11 +84,6 @@
         addView(view);
     }
 
-    public void init(OnClickListener clickPrimary, OnLongClickListener longClick) {
-        setOnClickListener(clickPrimary);
-        setOnLongClickListener(longClick);
-    }
-
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
         mLabel.setText(state.label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 3cd9e67..0709992 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,13 +15,18 @@
  */
 package com.android.systemui.qs.external;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.provider.Settings;
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
@@ -156,8 +161,22 @@
     }
 
     @Override
-    protected void handleUserSwitch(int newUserId) {
-        super.handleUserSwitch(newUserId);
+    public Intent getLongClickIntent() {
+        Intent i = new Intent(TileService.ACTION_QS_TILE_PREFERENCES);
+        i.setPackage(mComponent.getPackageName());
+        i = resolveIntent(i);
+        if (i != null) {
+            return i;
+        }
+        return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+                Uri.fromParts("package", mComponent.getPackageName(), null));
+    }
+
+    private Intent resolveIntent(Intent i) {
+        ResolveInfo result = mContext.getPackageManager().resolveActivityAsUser(i, 0,
+                ActivityManager.getCurrentUser());
+        return result != null ? new Intent(TileService.ACTION_QS_TILE_PREFERENCES)
+                .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
     }
 
     @Override
@@ -184,10 +203,6 @@
     }
 
     @Override
-    protected void handleLongClick() {
-    }
-
-    @Override
     protected void handleUpdateState(State state, Object arg) {
         Drawable drawable = mTile.getIcon().loadDrawable(mContext);
         int color = mContext.getColor(getColor(mTile.getState()));
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 5222e61..f0860fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.provider.Settings;
 import android.provider.Settings.Global;
 
 import com.android.internal.logging.MetricsLogger;
@@ -68,6 +69,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
         final boolean airplaneMode = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 6a9d826..93e075d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.provider.Settings;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.RelativeSizeSpan;
@@ -91,6 +92,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+    }
+
+    @Override
     protected void handleClick() {
         showDetail(true);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index c4b7944..80f667c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         if (!mController.canConfigBluetooth()) {
             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 15e082a..e0ad002 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -86,6 +86,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_CAST_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
             mHost.startRunnableDismissingKeyguard(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 15617c7f..5f87741 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -37,7 +37,7 @@
 
 /** Quick settings tile: Cellular **/
 public class CellularTile extends QSTile<QSTile.SignalState> {
-    private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+    static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
             "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
 
     private final NetworkController mController;
@@ -78,6 +78,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return CELLULAR_SETTINGS;
+    }
+
+    @Override
     protected void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory());
         if (mDataController.isMobileDataSupported()) {
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 e98734c..42ce69c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Intent;
+import android.provider.Settings;
 import android.provider.Settings.Secure;
 
 import com.android.internal.logging.MetricsLogger;
@@ -70,6 +72,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         mSetting.setValue(mState.value ? 0 : 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index c6a98b4..a1789a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Intent;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
@@ -44,6 +45,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return CellularTile.CELLULAR_SETTINGS;
+    }
+
+    @Override
     protected void handleClick() {
         mState.value = !mDataSaverController.isDataSaverEnabled();
         mDataSaverController.setDataSaverEnabled(mState.value);
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 29ca06b..8982b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,11 +29,13 @@
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
+import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.SysUIToast;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.volume.ZenModePanel;
@@ -99,7 +101,20 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return ZEN_SETTINGS;
+    }
+
+    @Override
     public void handleClick() {
+        if (mController.isVolumeRestricted()) {
+            // Collapse the panels, so the user can see the toast.
+            mHost.collapsePanels();
+            SysUIToast.makeText(mContext, mContext.getString(
+                    com.android.internal.R.string.error_message_change_not_allowed),
+                    Toast.LENGTH_LONG).show();
+            return;
+        }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         if (mState.value) {
             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
@@ -116,8 +131,7 @@
         final boolean newValue = zen != Global.ZEN_MODE_OFF;
         final boolean valueChanged = state.value != newValue;
         state.value = newValue;
-        state.disabledByPolicy = mController.isVolumeRestricted();
-        checkIfRestrictionEnforced(state, UserManager.DISALLOW_ADJUST_VOLUME);
+        checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
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 f06634e..c10843a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -18,6 +18,8 @@
 
 import android.app.ActivityManager;
 
+import android.content.Intent;
+import android.provider.MediaStore;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -60,6 +62,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+    }
+
+    @Override
     protected void handleClick() {
         if (ActivityManager.isUserAMonkey()) {
             return;
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 943b502..ad1c7a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Intent;
 import android.os.UserManager;
 
+import android.provider.Settings;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -58,6 +60,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         final boolean isEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
@@ -68,8 +75,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
-        state.disabledByPolicy = mController.isTetheringAllowed();
-        checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
+        checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
         if (arg instanceof Boolean) {
             state.value = (boolean) arg;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index bdf95d8..bb5ff8e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -92,6 +92,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
     protected void handleLongClick() {
         sendIntent("long-click", mOnLongClick, mOnLongClickUri);
     }
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 9f41f9a..6533252 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Intent;
 import android.os.UserManager;
 
+import android.provider.Settings;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -61,6 +63,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && mKeyguard.isShowing()) {
             mHost.startRunnableDismissingKeyguard(new Runnable() {
@@ -87,8 +94,7 @@
         // bug is fixed, this should be reverted to only hiding it on secure lock screens:
         // state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
         state.value = locationEnabled;
-        state.disabledByPolicy = mController.isUserLocationRestricted();
-        checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
+        checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
         if (locationEnabled) {
             state.icon = mEnable;
             state.label = mContext.getString(R.string.quick_settings_location_label);
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 c94cf5a..b267ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -17,8 +17,10 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 
+import android.provider.Settings;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -60,6 +62,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         if (mController == null) return;
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index ba7ea4d..f1066c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -16,7 +16,9 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.provider.Settings;
 import android.util.Pair;
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -42,6 +44,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_USER_SETTINGS);
+    }
+
+    @Override
     protected void handleClick() {
         showDetail(true);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 7a58f15..7ee795f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -93,6 +93,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return WIFI_SETTINGS;
+    }
+
+    @Override
     protected void handleSecondaryClick() {
         // Secondary clicks are header clicks, just toggle.
         mState.copyTo(mStateBeforeClick);
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 053a98a..003e9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Intent;
+import android.provider.Settings;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -52,6 +54,11 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_SYNC_SETTINGS);
+    }
+
+    @Override
     public void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         mProfileController.setWorkModeEnabled(!mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index fe504fe..3f0630d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -494,7 +494,7 @@
      * onChildDismissed() calls.
      */
     @Override
-    public void onChildSnappedBack(View v) {
+    public void onChildSnappedBack(View v, float targetLeft) {
         TaskView tv = (TaskView) v;
 
         // Re-enable clipping with the stack
@@ -517,11 +517,6 @@
     }
 
     @Override
-    public View getChildContentView(View v) {
-        return v;
-    }
-
-    @Override
     public boolean isAntiFalsingNeeded() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2bebac2..411fd08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -103,6 +103,7 @@
 import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.util.ArrayList;
@@ -115,7 +116,7 @@
 public abstract class BaseStatusBar extends SystemUI implements
         CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
-        ExpandableNotificationRow.OnExpandClickListener {
+        ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
@@ -220,6 +221,7 @@
 
     // which notification is currently being longpress-examined by the user
     private NotificationGuts mNotificationGutsExposed;
+    private ExpandableNotificationRow mNotificationGearDisplayed;
 
     private KeyboardShortcuts mKeyboardShortcuts;
 
@@ -1008,6 +1010,10 @@
         guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
     }
 
+    protected GearDisplayedListener getGearDisplayedListener() {
+        return this;
+    }
+
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
         return new SwipeHelper.LongPressListener() {
             @Override
@@ -1020,7 +1026,7 @@
                     return false;
                 }
 
-                ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+                final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
                 bindGuts(row);
 
                 // Assume we are a status_bar_notification_row
@@ -1052,6 +1058,14 @@
                                 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
                         a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
                         a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+                        a.addListener(new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                super.onAnimationEnd(animation);
+                                // Move the notification view back over the gear
+                                row.resetTranslation();
+                            }
+                        });
                         a.start();
                         guts.setExposed(true);
                         mStackScroller.onHeightChanged(null, true /* needsAnimation */);
@@ -1063,6 +1077,11 @@
         };
     }
 
+    @Override
+    public void onGearDisplayed(ExpandableNotificationRow row) {
+        mNotificationGearDisplayed = row;
+    }
+
     public void dismissPopups() {
         dismissPopups(-1, -1);
     }
@@ -1095,6 +1114,11 @@
             v.setExposed(false);
             mStackScroller.onHeightChanged(null, true /* needsAnimation */);
         }
+
+        if (mNotificationGearDisplayed != null) {
+            mNotificationGearDisplayed.resetTranslation();
+            mNotificationGearDisplayed = null;
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7422902e..94511da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,6 +16,12 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Notification;
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
@@ -45,6 +51,7 @@
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 import com.android.systemui.statusbar.stack.StackViewState;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class ExpandableNotificationRow extends ActivatableNotificationView {
@@ -87,6 +94,8 @@
      */
     private boolean mOnKeyguard;
 
+    private AnimatorSet mTranslateAnim;
+    private ArrayList<View> mTranslateableViews;
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
@@ -96,6 +105,7 @@
     private ExpansionLogger mLogger;
     private String mLoggingKey;
     private boolean mWasReset;
+    private NotificationSettingsIconRow mSettingsIconRow;
     private NotificationGuts mGuts;
     private NotificationData.Entry mEntry;
     private StatusBarNotification mStatusBarNotification;
@@ -108,6 +118,7 @@
     private boolean mChildrenExpanded;
     private boolean mIsSummaryWithChildren;
     private NotificationChildrenContainer mChildrenContainer;
+    private ViewStub mSettingsIconRowStub;
     private ViewStub mGutsStub;
     private boolean mIsSystemChildExpanded;
     private boolean mIsPinned;
@@ -527,6 +538,17 @@
             mGuts.setVisibility(oldGuts.getVisibility());
             addView(mGuts, index);
         }
+        if (mSettingsIconRow != null) {
+            View oldSettings = mSettingsIconRow;
+            int settingsIndex = indexOfChild(oldSettings);
+            removeView(oldSettings);
+            mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
+                    R.layout.notification_settings_icon_row, this, false);
+            mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+            mSettingsIconRow.setVisibility(oldSettings.getVisibility());
+            addView(mSettingsIconRow, settingsIndex);
+
+        }
         mPrivateLayout.reInflateViews();
         mPublicLayout.reInflateViews();
     }
@@ -573,6 +595,7 @@
         mPublicLayout.reset(mIsHeadsUp);
         mPrivateLayout.reset(mIsHeadsUp);
         resetHeight();
+        resetTranslation();
         logExpansionEvent(false, wasExpanded);
     }
 
@@ -596,6 +619,14 @@
         mPrivateLayout.setExpandClickListener(mExpandClickListener);
         mPrivateLayout.setContainingNotification(this);
         mPublicLayout.setExpandClickListener(mExpandClickListener);
+        mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
+        mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+            @Override
+            public void onInflate(ViewStub stub, View inflated) {
+                mSettingsIconRow = (NotificationSettingsIconRow) inflated;
+                mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+            }
+        });
         mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
         mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
             @Override
@@ -603,6 +634,7 @@
                 mGuts = (NotificationGuts) inflated;
                 mGuts.setClipTopAmount(getClipTopAmount());
                 mGuts.setActualHeight(getActualHeight());
+                mTranslateableViews.add(mGuts);
                 mGutsStub = null;
             }
         });
@@ -613,9 +645,89 @@
             public void onInflate(ViewStub stub, View inflated) {
                 mChildrenContainer = (NotificationChildrenContainer) inflated;
                 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+                mTranslateableViews.add(mChildrenContainer);
             }
         });
         mVetoButton = findViewById(R.id.veto);
+
+        // Add the views that we translate to reveal the gear
+        mTranslateableViews = new ArrayList<View>();
+        for (int i = 0; i < getChildCount(); i++) {
+            mTranslateableViews.add(getChildAt(i));
+        }
+        // Remove views that don't translate
+        mTranslateableViews.remove(mVetoButton);
+        mTranslateableViews.remove(mSettingsIconRowStub);
+        mTranslateableViews.remove(mChildrenContainerStub);
+        mTranslateableViews.remove(mGutsStub);
+    }
+
+    public void setTranslationForOutline(float translationX) {
+        setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
+    }
+
+    public void resetTranslation() {
+        if (mTranslateableViews != null) {
+            for (int i = 0; i < mTranslateableViews.size(); i++) {
+                mTranslateableViews.get(i).setTranslationX(0);
+            }
+            setTranslationForOutline(0);
+        }
+        if (mSettingsIconRow != null) {
+            mSettingsIconRow.resetState();
+        }
+    }
+
+    public void animateTranslateNotification(final float leftTarget) {
+        if (mTranslateAnim != null) {
+            mTranslateAnim.cancel();
+        }
+        AnimatorSet set = new AnimatorSet();
+        if (mTranslateableViews != null) {
+            for (int i = 0; i < mTranslateableViews.size(); i++) {
+                final View animView = mTranslateableViews.get(i);
+                final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
+                        animView, "translationX", leftTarget);
+                if (i == 0) {
+                    translateAnim.addUpdateListener(new AnimatorUpdateListener() {
+                        @Override
+                        public void onAnimationUpdate(ValueAnimator animation) {
+                            setTranslationForOutline((float) animation.getAnimatedValue());
+                        }
+                    });
+                }
+                translateAnim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator anim) {
+                        if (mSettingsIconRow != null && leftTarget == 0) {
+                            mSettingsIconRow.resetState();
+                        }
+                        mTranslateAnim = null;
+                    }
+                });
+                set.play(translateAnim);
+            }
+        }
+        mTranslateAnim = set;
+        set.start();
+    }
+
+    public float getSpaceForGear() {
+        if (mSettingsIconRow != null) {
+            return mSettingsIconRow.getSpaceForGear();
+        }
+        return 0;
+    }
+
+    public NotificationSettingsIconRow getSettingsRow() {
+        if (mSettingsIconRow == null) {
+            mSettingsIconRowStub.inflate();
+        }
+        return mSettingsIconRow;
+    }
+
+    public ArrayList<View> getContentViews() {
+        return mTranslateableViews;
     }
 
     public void inflateGuts() {
@@ -772,7 +884,7 @@
                 if (mIsSummaryWithChildren) {
                     mChildrenContainer.updateGroupOverflow();
                 }
-                notifyHeightChanged(false  /* needsAnimation */);
+                notifyHeightChanged(false /* needsAnimation */);
             }
         }
     }
@@ -1097,6 +1209,7 @@
             mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
                     mNotificationHeader);
             addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
+            mTranslateableViews.add(mNotificationHeader);
         } else {
             header.reapply(getContext(), mNotificationHeader);
             mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 44c6a5d..782a38c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -81,8 +81,13 @@
     }
 
     protected void setOutlineRect(float left, float top, float right, float bottom) {
+        setOutlineRect(true, left, top, right, bottom);
+    }
+
+    protected void setOutlineRect(boolean clipToOutline, float left, float top, float right,
+            float bottom) {
         mCustomOutline = true;
-        setClipToOutline(true);
+        setClipToOutline(clipToOutline);
 
         mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 7346bec..fe84d813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -49,9 +49,7 @@
     private int mClipTopAmount;
     private int mActualHeight;
     private boolean mExposed;
-    private RadioButton mApplyToTopic;
     private SeekBar mSeekBar;
-    private Notification.Topic mTopic;
     private INotificationManager mINotificationManager;
     private int mStartingImportance;
 
@@ -109,24 +107,9 @@
         mStartingImportance = importance;
         mINotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        mTopic = sbn.getNotification().getTopic() == null
-                ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
-                com.android.internal.R.string.default_notification_topic_label))
-                : sbn.getNotification().getTopic();
-        boolean doesUserUseTopics = false;
-        try {
-            doesUserUseTopics =
-                    mINotificationManager.doesUserUseTopics(sbn.getPackageName(), sbn.getUid());
-        } catch (RemoteException e) {}
-        final boolean userUsesTopics = doesUserUseTopics;
 
-        mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
-        if (userUsesTopics) {
-            mApplyToTopic.setChecked(true);
-        }
-        final View applyToApp = row.findViewById(R.id.apply_to_app);
-        final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
-        final TextView topicTitle = ((TextView) row.findViewById(R.id.title));
+        final TextView importanceSummary = ((TextView) row.findViewById(R.id.summary));
+        final TextView importanceTitle = ((TextView) row.findViewById(R.id.title));
         mSeekBar = (SeekBar) row.findViewById(R.id.seekbar);
         boolean systemApp = false;
         try {
@@ -156,12 +139,6 @@
                 updateTitleAndSummary(progress);
                 if (fromUser) {
                     MetricsLogger.action(mContext, MetricsEvent.ACTION_MODIFY_IMPORTANCE_SLIDER);
-                    if (userUsesTopics) {
-                        mApplyToTopic.setVisibility(View.VISIBLE);
-                        mApplyToTopic.setText(
-                                mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
-                        applyToApp.setVisibility(View.VISIBLE);
-                    }
                 }
             }
 
@@ -178,29 +155,29 @@
             private void updateTitleAndSummary(int progress) {
                 switch (progress) {
                     case NotificationListenerService.Ranking.IMPORTANCE_NONE:
-                        topicSummary.setText(mContext.getString(
+                        importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_blocked));
-                        topicTitle.setText(mContext.getString(R.string.blocked_importance));
+                        importanceTitle.setText(mContext.getString(R.string.blocked_importance));
                         break;
                     case NotificationListenerService.Ranking.IMPORTANCE_LOW:
-                        topicSummary.setText(mContext.getString(
+                        importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_low));
-                        topicTitle.setText(mContext.getString(R.string.low_importance));
+                        importanceTitle.setText(mContext.getString(R.string.low_importance));
                         break;
                     case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
-                        topicSummary.setText(mContext.getString(
+                        importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_default));
-                        topicTitle.setText(mContext.getString(R.string.default_importance));
+                        importanceTitle.setText(mContext.getString(R.string.default_importance));
                         break;
                     case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
-                        topicSummary.setText(mContext.getString(
+                        importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_high));
-                        topicTitle.setText(mContext.getString(R.string.high_importance));
+                        importanceTitle.setText(mContext.getString(R.string.high_importance));
                         break;
                     case NotificationListenerService.Ranking.IMPORTANCE_MAX:
-                        topicSummary.setText(mContext.getString(
+                        importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_max));
-                        topicTitle.setText(mContext.getString(R.string.max_importance));
+                        importanceTitle.setText(mContext.getString(R.string.max_importance));
                         break;
                 }
             }
@@ -213,8 +190,7 @@
         MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
                 progress - mStartingImportance);
         try {
-            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
-                    mApplyToTopic.isChecked() ? mTopic : null, progress);
+            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
         } catch (RemoteException e) {
             // :(
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
new file mode 100644
index 0000000..8fcd455
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 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.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
+
+    public interface SettingsIconRowListener {
+        /**
+         * Called when the gear behind a notification is touched.
+         */
+        public void onGearTouched(ExpandableNotificationRow row);
+    }
+
+    private ExpandableNotificationRow mParent;
+    private AlphaOptimizedImageView mGearIcon;
+    private float mHorizSpaceForGear;
+    private SettingsIconRowListener mListener;
+
+    private ValueAnimator mFadeAnimator;
+    private boolean mSettingsFadedIn = false;
+    private boolean mAnimating = false;
+    private boolean mOnLeft = true;
+
+    public NotificationSettingsIconRow(Context context) {
+        this(context, null);
+    }
+
+    public NotificationSettingsIconRow(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mGearIcon = (AlphaOptimizedImageView) findViewById(R.id.gear_icon);
+        mGearIcon.setOnClickListener(this);
+
+        final float iconMargin =
+                ((ViewGroup.MarginLayoutParams) mGearIcon.getLayoutParams()).getMarginStart();
+        final float iconWidth =
+                getResources().getDimensionPixelOffset(R.dimen.notification_gear_size);
+        mHorizSpaceForGear = (iconWidth + iconMargin * 2);
+        resetState();
+    }
+
+    public void setGearListener(SettingsIconRowListener listener) {
+        mListener = listener;
+    }
+
+    public void setNotificationRowParent(ExpandableNotificationRow parent) {
+        mParent = parent;
+    }
+
+    public ExpandableNotificationRow getNotificationParent() {
+        return mParent;
+    }
+
+    public void resetState() {
+        setGearAlpha(0f);
+        mAnimating = false;
+        setIconLocation(true /* on left */);
+    }
+
+    private void setGearAlpha(float alpha) {
+        if (alpha == 0) {
+            mSettingsFadedIn = false; // Can fade in again once it's gone.
+            mGearIcon.setVisibility(View.INVISIBLE);
+        } else {
+            if (alpha == 1) {
+                mSettingsFadedIn = true;
+            }
+            mGearIcon.setVisibility(View.VISIBLE);
+        }
+        mGearIcon.setAlpha(alpha);
+    }
+
+    /**
+     * Returns the horizontal space in pixels required to display the gear behind a notification.
+     */
+    public float getSpaceForGear() {
+        return mHorizSpaceForGear;
+    }
+
+    /**
+     * Indicates whether the gear is visible at 1 alpha. Does not indicate
+     * if entire view is visible.
+     */
+    public boolean isVisible() {
+        return mSettingsFadedIn;
+    }
+
+    public void cancelFadeAnimator() {
+        if (mFadeAnimator != null) {
+            mFadeAnimator.cancel();
+        }
+    }
+
+    public void updateSettingsIcons(final float transX, final float size) {
+        if (mAnimating || (mGearIcon.getAlpha() == 0)) {
+            // Don't adjust when animating or settings aren't visible
+            return;
+        }
+        setIconLocation(transX > 0 /* fromLeft */);
+        final float fadeThreshold = size * 0.3f;
+        final float absTrans = Math.abs(transX);
+        float desiredAlpha = 0;
+
+        // if ((fromLeft && transX <= fadeThreshold) || (!fromLeft && absTrans <= fadeThreshold)) {
+        if (absTrans <= fadeThreshold) {
+            desiredAlpha = 1;
+        } else {
+            desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
+        }
+        setGearAlpha(desiredAlpha);
+    }
+
+    public void fadeInSettings(final boolean fromLeft, final float transX,
+            final float notiThreshold) {
+        setIconLocation(transX > 0 /* fromLeft */);
+        mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
+        mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float absTrans = Math.abs(transX);
+
+                boolean pastGear = (fromLeft && transX <= notiThreshold)
+                        || (!fromLeft && absTrans <= notiThreshold);
+                if (pastGear && !mSettingsFadedIn) {
+                    setGearAlpha((float) animation.getAnimatedValue());
+                }
+            }
+        });
+        mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                mAnimating = false;
+                mSettingsFadedIn = false;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                mAnimating = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                mAnimating = false;
+                mSettingsFadedIn = true;
+            }
+        });
+        mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
+        mFadeAnimator.setDuration(200);
+        mFadeAnimator.start();
+    }
+
+    @Override
+    public void onClick(View v) {
+        mListener.onGearTouched(mParent);
+    }
+
+    private void setIconLocation(boolean onLeft) {
+        if (onLeft == mOnLeft) {
+            // Same side? Do nothing.
+            return;
+        }
+        mGearIcon.setTranslationX(onLeft ? 0 : (getWidth() - mHorizSpaceForGear));
+        mOnLeft = onLeft;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
new file mode 100644
index 0000000..4f3c61e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 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.statusbar.phone;
+
+import android.app.ActivityManager;
+import android.app.IWallpaperManager;
+import android.app.IWallpaperManagerCallback;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+/**
+ * Manages the lockscreen wallpaper.
+ */
+public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable {
+
+    private static final String TAG = "LockscreenWallpaper";
+
+    private final Context mContext;
+    private final PhoneStatusBar mBar;
+    private final IWallpaperManager mService;
+    private final Handler mH;
+
+    private boolean mCached;
+    private Bitmap mCache;
+    private int mUserId;
+
+    public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
+        mContext = ctx;
+        mBar = bar;
+        mH = h;
+        mService = IWallpaperManager.Stub.asInterface(
+                ServiceManager.getService(Context.WALLPAPER_SERVICE));
+        mUserId = ActivityManager.getCurrentUser();
+
+        try {
+            mService.setLockWallpaperCallback(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "System dead?" + e);
+        }
+    }
+
+    public Bitmap getBitmap() {
+        try {
+            if (mCached) {
+                return mCache;
+            }
+            if (!mService.isWallpaperSupported(mContext.getOpPackageName())) {
+                mCached = true;
+                mCache = null;
+                return null;
+            }
+            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+                    new Bundle(), mUserId);
+            if (fd != null) {
+                try {
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    mCache = BitmapFactory.decodeFileDescriptor(
+                            fd.getFileDescriptor(), null, options);
+                    mCached = true;
+                    return mCache;
+                } catch (OutOfMemoryError e) {
+                    Log.w(TAG, "Can't decode file", e);
+                    return null;
+                } finally {
+                    IoUtils.closeQuietly(fd);
+                }
+            } else {
+                mCached = true;
+                mCache = null;
+                return null;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "System dead?" + e);
+            return null;
+        }
+    }
+
+    public void setUser(int user) {
+        if (user != mUserId) {
+            mCached = false;
+            mUserId = user;
+        }
+    }
+
+    @Override
+    public void onWallpaperChanged() {
+        // Called on Binder thread.
+        mH.removeCallbacks(this);
+        mH.post(this);
+    }
+
+    @Override
+    public void run() {
+        // Called in response to onWallpaperChanged on the main thread.
+        mCached = false;
+        mCache = null;
+        getBitmap();
+        mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 401d405..032957f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -23,6 +23,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.IWallpaperManagerCallback;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -248,9 +249,7 @@
     private static final boolean ONLY_CORE_APPS;
 
     /** If true, the lockscreen will show a distinct wallpaper */
-    private static final boolean ENABLE_LOCKSCREEN_WALLPAPER =
-            !ActivityManager.isLowRamDeviceStatic()
-                    && SystemProperties.getBoolean("debug.lockscreen_wallpaper", false);
+    private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
 
     /* If true, the device supports freeform window management.
      * This affects the status bar UI. */
@@ -296,6 +295,7 @@
     AccessibilityController mAccessibilityController;
     FingerprintUnlockController mFingerprintUnlockController;
     LightStatusBarController mLightStatusBarController;
+    private LockscreenWallpaper mLockscreenWallpaper;
 
     int mNaturalBarHeight = -1;
 
@@ -746,6 +746,7 @@
         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                 R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
+        mStackScroller.setGearDisplayedListener(getGearDisplayedListener());
         mStackScroller.setPhoneStatusBar(this);
         mStackScroller.setGroupManager(mGroupManager);
         mStackScroller.setHeadsUpManager(mHeadsUpManager);
@@ -792,6 +793,10 @@
                 mKeyguardBottomArea.getLockIcon());
         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
 
+        if (ENABLE_LOCKSCREEN_WALLPAPER) {
+            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
+        }
+
         // set the initial view visibility
         setAreThereNotifications();
 
@@ -1819,7 +1824,7 @@
     };
 
     /**
-     * Refresh or remove lockscreen artwork from media metadata.
+     * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
      */
     public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
         if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
@@ -1847,10 +1852,7 @@
             }
         }
         if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
-            // TODO: use real lockscreen wallpaper.
-            WallpaperManager wallpaperManager = mContext
-                    .getSystemService(WallpaperManager.class);
-            artworkBitmap = wallpaperManager.getBitmap();
+            artworkBitmap = mLockscreenWallpaper.getBitmap();
         }
 
         final boolean hasArtwork = artworkBitmap != null;
@@ -3084,10 +3086,6 @@
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 notifyNavigationBarScreenOn(true);
             }
-            else if (ENABLE_LOCKSCREEN_WALLPAPER
-                    && Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
-                updateMediaMetaData(true, true);
-            }
         }
     };
 
@@ -3173,6 +3171,7 @@
         resetUserSetupObserver();
         setControllerUsers();
         clearCurrentMediaNotification();
+        mLockscreenWallpaper.setUser(newUserId);
         updateMediaMetaData(true, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 500d603..047f14d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -21,7 +21,6 @@
     void removeCallback(Callback callback);
     boolean isHotspotEnabled();
     void setHotspotEnabled(boolean enabled);
-    boolean isTetheringAllowed();
 
     public interface Callback {
         void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 07b7409..f03d9e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,15 +16,12 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -40,8 +37,6 @@
     private final Receiver mReceiver = new Receiver();
     private final ConnectivityManager mConnectivityManager;
     private final Context mContext;
-    private final UserManager mUserManager;
-    private final int mCurrentUser;
 
     private int mHotspotState;
 
@@ -49,8 +44,6 @@
         mContext = context;
         mConnectivityManager = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mCurrentUser = ActivityManager.getCurrentUser();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,12 +88,6 @@
         return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
     }
 
-    @Override
-    public boolean isTetheringAllowed() {
-        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
-                UserHandle.of(mCurrentUser));
-    }
-
     static final class OnStartTetheringCallback extends
             ConnectivityManager.OnStartTetheringCallback {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 401943e..29a8981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,7 +21,6 @@
     boolean setLocationEnabled(boolean enabled);
     void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
     void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
-    boolean isUserLocationRestricted();
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 436a40d..8d84be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,7 +52,6 @@
 
     private AppOpsManager mAppOpsManager;
     private StatusBarManager mStatusBarManager;
-    private final int mCurrentUser;
 
     private boolean mAreActiveLocationRequests;
 
@@ -74,7 +73,6 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mStatusBarManager
                 = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
-        mCurrentUser = ActivityManager.getCurrentUser();
 
         // Examine the current location state and initialize the status view.
         updateActiveLocationRequests();
@@ -105,6 +103,10 @@
      * @return true if attempt to change setting was successful.
      */
     public boolean setLocationEnabled(boolean enabled) {
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (isUserLocationRestricted(currentUserId)) {
+            return false;
+        }
         final ContentResolver cr = mContext.getContentResolver();
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
@@ -113,7 +115,7 @@
         // QuickSettings always runs as the owner, so specifically set the settings
         // for the current foreground user.
         return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
     }
 
     /**
@@ -131,10 +133,10 @@
     /**
      * Returns true if the current user is restricted from using location.
      */
-    public boolean isUserLocationRestricted() {
+    private boolean isUserLocationRestricted(int userId) {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
-                UserHandle.of(mCurrentUser));
+                UserHandle.of(userId));
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6ca7dc8..13369f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -210,12 +210,16 @@
                     }
                 }
 
+                boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
+                                UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
                 boolean currentUserCanCreateUsers = currentUserInfo != null
                         && (currentUserInfo.isAdmin()
-                                || currentUserInfo.id == UserHandle.USER_SYSTEM);
-                boolean canCreateGuest = (currentUserCanCreateUsers || addUsersWhenLocked)
+                                || currentUserInfo.id == UserHandle.USER_SYSTEM)
+                        && systemCanCreateUsers;
+                boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
+                boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
                         && guestRecord == null;
-                boolean canCreateUser = (currentUserCanCreateUsers || addUsersWhenLocked)
+                boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
                         && mUserManager.canAddMoreUsers();
                 boolean createIsRestricted = !addUsersWhenLocked;
 
@@ -225,7 +229,7 @@
                             guestRecord = new UserRecord(null /* info */, null /* picture */,
                                     true /* isGuest */, false /* isCurrent */,
                                     false /* isAddUser */, createIsRestricted);
-                            checkIfAddUserDisallowed(guestRecord);
+                            checkIfAddUserDisallowedByAdminOnly(guestRecord);
                             records.add(guestRecord);
                         }
                     } else {
@@ -238,7 +242,7 @@
                     UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
                             createIsRestricted);
-                    checkIfAddUserDisallowed(addUserRecord);
+                    checkIfAddUserDisallowedByAdminOnly(addUserRecord);
                     records.add(addUserRecord);
                 }
 
@@ -615,10 +619,11 @@
         }
     }
 
-    private void checkIfAddUserDisallowed(UserRecord record) {
+    private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
         EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
                 UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
-        if (admin != null) {
+        if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
             record.isDisabledByAdmin = true;
             record.enforcedAdmin = admin;
         } else {
@@ -683,7 +688,7 @@
     }
 
     public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
-        private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
+        private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
 
         @Override
         public CharSequence getTitle() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index bf4245b..f078b53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,10 +18,12 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -32,6 +34,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
@@ -56,6 +59,8 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.NotificationSettingsIconRow;
+import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -72,7 +77,8 @@
  */
 public class NotificationStackScrollLayout extends ViewGroup
         implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
-        ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
+        ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
+        SettingsIconRowListener {
 
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
@@ -207,6 +213,11 @@
      */
     private int mMaxScrollAfterExpand;
     private SwipeHelper.LongPressListener mLongPressListener;
+    private GearDisplayedListener mGearDisplayedListener;
+
+    private NotificationSettingsIconRow mCurrIconRow;
+    private View mTranslatingParentView;
+    private View mGearExposedView;
 
     /**
      * Should in this touch motion only be scrolling allowed? It's true when the scroller was
@@ -304,8 +315,7 @@
                 minHeight, maxHeight);
         mExpandHelper.setEventSource(this);
         mExpandHelper.setScrollAdapter(this);
-
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
+        mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
         mSwipeHelper.setLongPressListener(mLongPressListener);
         mStackScrollAlgorithm = new StackScrollAlgorithm(context);
         initView(context);
@@ -321,6 +331,13 @@
     }
 
     @Override
+    public void onGearTouched(ExpandableNotificationRow row) {
+        if (mLongPressListener != null) {
+            mLongPressListener.onLongPress(row, 0, 0);
+        }
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
         if (DEBUG) {
@@ -630,6 +647,10 @@
         mLongPressListener = listener;
     }
 
+    public void setGearDisplayedListener(GearDisplayedListener listener) {
+        mGearDisplayedListener = listener;
+    }
+
     public void setQsContainer(ViewGroup qsContainer) {
         mQsContainer = qsContainer;
     }
@@ -666,7 +687,7 @@
     }
 
     @Override
-    public void onChildSnappedBack(View animView) {
+    public void onChildSnappedBack(View animView, float targetLeft) {
         mAmbientState.onDragFinished(animView);
         if (!mDragAnimPendingChildren.contains(animView)) {
             if (mAnimationsEnabled) {
@@ -678,6 +699,13 @@
             // We start the swipe and snap back in the same frame, we don't want any animation
             mDragAnimPendingChildren.remove(animView);
         }
+
+        if (targetLeft == 0 && mCurrIconRow != null) {
+            mCurrIconRow.resetState();
+            if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
+                mGearExposedView = null;
+            }
+        }
     }
 
     @Override
@@ -686,7 +714,7 @@
             mScrimController.setTopHeadsUpDragAmount(animView,
                     Math.min(Math.abs(swipeProgress - 1.0f), 1.0f));
         }
-        return false;
+        return true; // Don't fade out the notification
     }
 
     public void onBeginDrag(View v) {
@@ -726,8 +754,21 @@
         return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
     }
 
+    @Override
     public View getChildAtPosition(MotionEvent ev) {
-        return getChildAtPosition(ev.getX(), ev.getY());
+        View child = getChildAtPosition(ev.getX(), ev.getY());
+        if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            ExpandableNotificationRow parent = row.getNotificationParent();
+            if (mGearExposedView != null && parent != null
+                    && parent.areChildrenExpanded() && mGearExposedView == parent) {
+                // In this case the group is expanded and showing the gear for the
+                // group, further interaction should apply to the group, not any
+                // child notifications so we use the parent of the child.
+                child = row.getNotificationParent();
+            }
+        }
+        return child;
     }
 
     public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
@@ -841,10 +882,6 @@
         return mScrollingEnabled;
     }
 
-    public View getChildContentView(View v) {
-        return v;
-    }
-
     public boolean canChildBeDismissed(View v) {
         return StackScrollAlgorithm.canChildBeDismissed(v);
     }
@@ -3008,6 +3045,9 @@
             disableClipOptimization();
         }
         handleDismissAllClipping();
+        if (mCurrIconRow != null & mCurrIconRow.isVisible()) {
+            mCurrIconRow.getNotificationParent().animateTranslateNotification(0 /* left target */);
+        }
     }
 
     private void handleDismissAllClipping() {
@@ -3268,6 +3308,247 @@
         public void flingTopOverscroll(float velocity, boolean open);
     }
 
+    /**
+     * A listener that is notified when the gear is shown behind a notification.
+     */
+    public interface GearDisplayedListener {
+        void onGearDisplayed(ExpandableNotificationRow row);
+    }
+
+    private class NotificationSwipeHelper extends SwipeHelper {
+        private static final int MOVE_STATE_LEFT = -1;
+        private static final int MOVE_STATE_UNDEFINED = 0;
+        private static final int MOVE_STATE_RIGHT = 1;
+
+        private static final long GEAR_SHOW_DELAY = 60;
+
+        private ArrayList<View> mTranslatingViews = new ArrayList<>();
+        private CheckForDrag mCheckForDrag;
+        private Handler mHandler;
+        private int mMoveState = MOVE_STATE_UNDEFINED;
+
+        public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
+            super(swipeDirection, callback, context);
+            mHandler = new Handler();
+        }
+
+        @Override
+        public void onDownUpdate(View currView) {
+            // Set the active view
+            mTranslatingParentView = currView;
+
+            // Reset check for drag gesture
+            mCheckForDrag = null;
+
+            // Slide back any notifications that might be showing a gear
+            resetExposedGearView();
+
+            if (currView instanceof ExpandableNotificationRow) {
+                // Set the listener for the current row's gear
+                mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
+                mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
+
+                // And the translating children
+                mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
+            }
+            mMoveState = MOVE_STATE_UNDEFINED;
+        }
+
+        @Override
+        public void onMoveUpdate(View view, float translation, float delta) {
+            final int newMoveState = (delta < 0) ? MOVE_STATE_RIGHT : MOVE_STATE_LEFT;
+            if (mMoveState != MOVE_STATE_UNDEFINED && mMoveState != newMoveState) {
+                // Changed directions, make sure we check for drag again.
+                mCheckForDrag = null;
+            }
+            mMoveState = newMoveState;
+
+            if (view instanceof ExpandableNotificationRow) {
+                ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
+                if (!isPinnedHeadsUp(view)) {
+                    // Only show the gear if we're not a heads up view.
+                    checkForDrag();
+                    if (mCurrIconRow != null) {
+                        mCurrIconRow.updateSettingsIcons(translation, getSize(view));
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void dismissChild(final View view, float velocity) {
+            cancelCheckForDrag();
+            super.dismissChild(view, velocity);
+        }
+
+        @Override
+        public void snapChild(final View animView, final float targetLeft, float velocity) {
+            final float snapBackThreshold = getSpaceForGear(animView);
+            final float translation = getTranslation(animView);
+            final boolean fromLeft = translation > 0;
+            final float absTrans = Math.abs(translation);
+            final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+
+            boolean pastGear = (fromLeft && translation >= snapBackThreshold * 0.4f
+                    && translation <= notiThreshold) ||
+                    (!fromLeft && absTrans >= snapBackThreshold * 0.4f
+                            && absTrans <= notiThreshold);
+
+            if (pastGear && !isPinnedHeadsUp(animView)) {
+                // bouncity
+                final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
+                mGearExposedView = mTranslatingParentView;
+                if (mGearDisplayedListener != null
+                        && (animView instanceof ExpandableNotificationRow)) {
+                    mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
+                }
+                super.snapChild(animView, target, velocity);
+            } else {
+                super.snapChild(animView, 0, velocity);
+            }
+        }
+
+        @Override
+        public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+            if (mDismissAllInProgress) {
+                // When dismissing all, we translate the entire view instead.
+                super.onTranslationUpdate(animView, value, canBeDismissed);
+                return;
+            }
+            if (animView instanceof ExpandableNotificationRow) {
+                ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
+            }
+            if (mCurrIconRow != null) {
+                mCurrIconRow.updateSettingsIcons(value, getSize(animView));
+            }
+        }
+
+        @Override
+        public Animator getViewTranslationAnimator(View v, float target,
+                AnimatorUpdateListener listener) {
+            if (mDismissAllInProgress) {
+                // When dismissing all, we translate the entire view instead.
+                return super.getViewTranslationAnimator(v, target, listener);
+            }
+            ArrayList<Animator> animators = new ArrayList<Animator>();
+            for (int i = 0; i < mTranslatingViews.size(); i++) {
+                ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
+                animators.add(anim);
+                if (i == 0 && listener != null) {
+                    anim.addUpdateListener(listener);
+                }
+            }
+            AnimatorSet set = new AnimatorSet();
+            set.playTogether(animators);
+            return set;
+        }
+
+        @Override
+        public void setTranslation(View v, float translate) {
+            if (mDismissAllInProgress) {
+                // When dismissing all, we translate the entire view instead.
+                super.setTranslation(v, translate);
+                return;
+            }
+            // Translate the group of views
+            for (int i = 0; i < mTranslatingViews.size(); i++) {
+                if (mTranslatingViews.get(i) != null) {
+                    super.setTranslation(mTranslatingViews.get(i), translate);
+                }
+            }
+        }
+
+        @Override
+        public float getTranslation(View v) {
+            if (mDismissAllInProgress) {
+                // When dismissing all, we translate the entire view instead.
+                return super.getTranslation(v);
+            }
+            // All of the views in the list should have same translation, just use first one.
+            if (mTranslatingViews.size() > 0) {
+                return super.getTranslation(mTranslatingViews.get(0));
+            }
+            return 0;
+        }
+
+
+        /**
+         * Returns the horizontal space in pixels required to display the gear behind a
+         * notification.
+         */
+        private float getSpaceForGear(View view) {
+            if (view instanceof ExpandableNotificationRow) {
+                return ((ExpandableNotificationRow) view).getSpaceForGear();
+            }
+            return 0;
+        }
+
+        private void checkForDrag() {
+            if (mCheckForDrag == null) {
+                mCheckForDrag = new CheckForDrag();
+                mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
+            }
+        }
+
+        private void cancelCheckForDrag() {
+            if (mCurrIconRow != null) {
+                mCurrIconRow.cancelFadeAnimator();
+            }
+            mHandler.removeCallbacks(mCheckForDrag);
+            mCheckForDrag = null;
+        }
+
+        private final class CheckForDrag implements Runnable {
+            @Override
+            public void run() {
+                final float translation = getTranslation(mTranslatingParentView);
+                final float absTransX = Math.abs(translation);
+                final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
+                final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+                if (mCurrIconRow != null && absTransX >= bounceBackToGearWidth * 0.4
+                        && absTransX < notiThreshold) {
+                    // Show icon
+                    mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
+                            notiThreshold);
+                } else {
+                    // Allow more to be posted if this wasn't a drag.
+                    mCheckForDrag = null;
+                }
+            }
+        }
+
+        private void resetExposedGearView() {
+            if (mGearExposedView == null || mGearExposedView == mTranslatingParentView) {
+                // If no gear is showing or it's showing for this view we do nothing.
+                return;
+            }
+
+            final View prevGearExposedView = mGearExposedView;
+            mGearExposedView = null;
+
+            AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+                public void onAnimationEnd(Animator animator) {
+                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
+                        ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
+                                .resetState();
+                    }
+                }
+            };
+            AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
+                        ((ExpandableNotificationRow) prevGearExposedView)
+                                .setTranslationForOutline((float) animation.getAnimatedValue());
+                    }
+                }
+            };
+            Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
+            set.addListener(listener);
+            set.start();
+        }
+    }
+
     static class AnimationEvent {
 
         static AnimationFilter[] FILTERS = new AnimationFilter[] {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
index 1377407..e9650ea 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -42,6 +42,9 @@
         Listener, OnPreferenceChangeListener {
 
     private static final String TAG = "NightModeFragment";
+
+    public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
+
     private static final CharSequence KEY_AUTO = "auto";
     private static final CharSequence KEY_DARK_THEME = "dark_theme";
     private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
index 1311f30..61135bd 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -16,6 +16,7 @@
 package com.android.systemui.tuner;
 
 import android.app.ActivityManager;
+import android.content.Intent;
 import android.provider.Settings;
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -60,6 +61,12 @@
     }
 
     @Override
+    public Intent getLongClickIntent() {
+        return new Intent(mContext, TunerActivity.class)
+                .putExtra(NightModeFragment.EXTRA_SHOW_NIGHT_MODE, true);
+    }
+
+    @Override
     protected void handleClick() {
         mNightModeController.setNightMode(!mNightModeController.isEnabled());
         refreshState();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 4225b48..def597d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,7 +36,10 @@
         super.onCreate(savedInstanceState);
 
         if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
-            getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+            boolean showNightMode = getIntent().getBooleanExtra(
+                    NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
+            getFragmentManager().beginTransaction().replace(R.id.content_frame,
+                    showNightMode ? new NightModeFragment() : new TunerFragment(),
                     TAG_TUNER).commit();
         }
     }
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
similarity index 84%
rename from services/core/java/com/android/server/notification/TopicImportanceExtractor.java
rename to services/core/java/com/android/server/notification/ImportanceExtractor.java
index c6b3e0f..885b9b7 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -21,7 +21,7 @@
 /**
  * Determines the importance of the given notification.
  */
-public class TopicImportanceExtractor implements NotificationSignalExtractor {
+public class ImportanceExtractor implements NotificationSignalExtractor {
     private static final String TAG = "ImportantTopicExtractor";
     private static final boolean DBG = false;
 
@@ -42,9 +42,8 @@
             return null;
         }
 
-        final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
-                record.sbn.getUid(), record.sbn.getNotification().getTopic());
-        record.setTopicImportance(topicImportance);
+        record.setUserImportance(
+                mConfig.getImportance(record.sbn.getPackageName(), record.sbn.getUid()));
 
         return null;
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ede1a2f..95198a3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -30,7 +30,6 @@
 import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
 import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
 import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED;
 import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
@@ -754,7 +753,7 @@
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
-                                    changeUserId, reason, null, null);
+                                    changeUserId, reason, null);
                         }
                     }
                 }
@@ -787,14 +786,14 @@
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
-                            REASON_USER_STOPPED, null, null);
+                            REASON_USER_STOPPED, null);
                 }
             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
                 boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (inQuietMode && userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
-                            REASON_PROFILE_TURNED_OFF, null, null);
+                            REASON_PROFILE_TURNED_OFF, null);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
@@ -1086,7 +1085,7 @@
         // Now, cancel any outstanding notifications that are part of a just-disabled app
         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
-                    REASON_PACKAGE_BANNED, null, null);
+                    REASON_PACKAGE_BANNED, null);
         }
     }
 
@@ -1250,7 +1249,7 @@
             // running foreground services.
             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
                     pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
-                    REASON_APP_CANCEL_ALL, null, null);
+                    REASON_APP_CANCEL_ALL, null);
         }
 
         @Override
@@ -1279,79 +1278,50 @@
         }
 
         @Override
-        public boolean hasBannedTopics(String pkg, int uid) {
+        public void setPriority(String pkg, int uid, int priority) {
             checkCallerIsSystem();
-            return mRankingHelper.hasBannedTopics(pkg, uid);
-        }
-
-        @Override
-        public ParceledListSlice<Notification.Topic> getTopics(String pkg, int uid) {
-            checkCallerIsSystem();
-            return new ParceledListSlice<Notification.Topic>(mRankingHelper.getTopics(pkg, uid));
-        }
-
-        @Override
-        public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
-            checkCallerIsSystem();
-            mRankingHelper.setPriority(pkg, uid, topic, priority);
+            mRankingHelper.setPriority(pkg, uid, priority);
             savePolicyFile();
         }
 
         @Override
-        public int getPriority(String pkg, int uid, Notification.Topic topic) {
+        public int getPriority(String pkg, int uid) {
             checkCallerIsSystem();
-            return mRankingHelper.getPriority(pkg, uid, topic);
+            return mRankingHelper.getPriority(pkg, uid);
         }
 
         @Override
-        public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
-                int visibility) {
+        public void setVisibilityOverride(String pkg, int uid, int visibility) {
             checkCallerIsSystem();
-            mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
+            mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
             savePolicyFile();
         }
 
         @Override
-        public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+        public int getVisibilityOverride(String pkg, int uid) {
             checkCallerIsSystem();
-            return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
+            return mRankingHelper.getVisibilityOverride(pkg, uid);
         }
 
         @Override
-        public void setImportance(String pkg, int uid, Notification.Topic topic,
-                int importance) {
+        public void setImportance(String pkg, int uid,  int importance) {
             enforceSystemOrSystemUI("Caller not system or systemui");
-            if (topic == null) {
-                // App wide, potentially store block in app ops.
-                setNotificationsEnabledForPackageImpl(pkg, uid,
-                        importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
-            } else {
-                if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
-                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
-                            UserHandle.getUserId(uid),
-                            REASON_TOPIC_BANNED, topic, null);
-                }
-            }
-            mRankingHelper.setImportance(pkg, uid, topic, importance);
+            setNotificationsEnabledForPackageImpl(pkg, uid,
+                    importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+            mRankingHelper.setImportance(pkg, uid, importance);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicImportance(String pkg, String topicId) {
+        public int getPackageImportance(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
-            return mRankingHelper.getImportance(pkg, Binder.getCallingUid(), topicId);
+            return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
         }
 
         @Override
-        public int getImportance(String pkg, int uid, Notification.Topic topic) {
+        public int getImportance(String pkg, int uid) {
             checkCallerIsSystem();
-            return mRankingHelper.getImportance(pkg, uid, topic);
-        }
-
-        @Override
-        public boolean doesUserUseTopics(String pkg, int uid) {
-            enforceSystemOrSystemUI("Caller not system or systemui");
-            return mRankingHelper.doesUserUseTopics(pkg, uid);
+            return mRankingHelper.getImportance(pkg, uid);
         }
 
         /**
@@ -2381,11 +2351,9 @@
 
                 mRankingHelper.extractSignals(r);
 
-                // why is this here?
-                savePolicyFile();
                 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
 
-                // blocked apps/topics
+                // blocked apps
                 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
                         || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
                     if (!isSystemNotification) {
@@ -3182,11 +3150,11 @@
     }
 
     /**
-     * Cancels all notifications from a given package or topic that have all of the
+     * Cancels all notifications from a given package that have all of the
      * {@code mustHaveFlags}.
      */
     boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
-            int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic,
+            int mustNotHaveFlags, boolean doit, int userId, int reason,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -3214,10 +3182,6 @@
                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
                     continue;
                 }
-                if (topic != null
-                        && !topic.getId().equals(r.getNotification().getTopic().getId())) {
-                    continue;
-                }
                 if (canceledNotifications == null) {
                     canceledNotifications = new ArrayList<>();
                 }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 2ca5534..25d17f6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -35,7 +35,6 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -92,12 +91,12 @@
     private int mAuthoritativeRank;
     private String mGlobalSortKey;
     private int mPackageVisibility;
-    private int mTopicImportance = IMPORTANCE_UNSPECIFIED;
+    private int mUserImportance = IMPORTANCE_UNSPECIFIED;
     private int mImportance = IMPORTANCE_UNSPECIFIED;
     private CharSequence mImportanceExplanation = null;
 
     private int mSuppressedVisualEffects = 0;
-    private String mTopicExplanation;
+    private String mUserExplanation;
     private String mPeopleExplanation;
 
     @VisibleForTesting
@@ -183,7 +182,7 @@
         mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
         mCreationTimeMs = previous.mCreationTimeMs;
         mVisibleSinceMs = previous.mVisibleSinceMs;
-        mTopicImportance = previous.mTopicImportance;
+        mUserImportance = previous.mUserImportance;
         mImportance = previous.mImportance;
         mImportanceExplanation = previous.mImportanceExplanation;
         // Don't copy mGlobalSortKey, recompute it.
@@ -275,8 +274,8 @@
         pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
         pw.println(prefix + "  mPackagePriority=" + mPackagePriority);
         pw.println(prefix + "  mPackageVisibility=" + mPackageVisibility);
-        pw.println(prefix + "  mTopicImportance="
-                + NotificationListenerService.Ranking.importanceToString(mTopicImportance));
+        pw.println(prefix + "  mUserImportance="
+                + NotificationListenerService.Ranking.importanceToString(mUserImportance));
         pw.println(prefix + "  mImportance="
                 + NotificationListenerService.Ranking.importanceToString(mImportance));
         pw.println(prefix + "  mImportanceExplanation=" + mImportanceExplanation);
@@ -357,17 +356,17 @@
         return mPackageVisibility;
     }
 
-    public void setTopicImportance(int importance) {
-        mTopicImportance = importance;
-        applyTopicImportance();
+    public void setUserImportance(int importance) {
+        mUserImportance = importance;
+        applyUserImportance();
     }
 
-    private String getTopicExplanation() {
-        if (mTopicExplanation == null) {
-            mTopicExplanation =
-                    mContext.getString(com.android.internal.R.string.importance_from_topic);
+    private String getUserExplanation() {
+        if (mUserExplanation == null) {
+            mUserExplanation =
+                    mContext.getString(com.android.internal.R.string.importance_from_user);
         }
-        return mTopicExplanation;
+        return mUserExplanation;
     }
 
     private String getPeopleExplanation() {
@@ -378,15 +377,15 @@
         return mPeopleExplanation;
     }
 
-    private void applyTopicImportance() {
-        if (mTopicImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
-            mImportance = mTopicImportance;
-            mImportanceExplanation = getTopicExplanation();
+    private void applyUserImportance() {
+        if (mUserImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
+            mImportance = mUserImportance;
+            mImportanceExplanation = getUserExplanation();
         }
     }
 
-    public int getTopicImportance() {
-        return mTopicImportance;
+    public int getUserImportance() {
+        return mUserImportance;
     }
 
     public void setImportance(int importance, CharSequence explanation) {
@@ -394,7 +393,7 @@
             mImportance = importance;
             mImportanceExplanation = explanation;
         }
-        applyTopicImportance();
+        applyUserImportance();
     }
 
     public int getImportance() {
@@ -529,6 +528,6 @@
     }
 
     public boolean isImportanceFromUser() {
-        return mImportance == mTopicImportance;
+        return mImportance == mUserImportance;
     }
 }
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/PriorityExtractor.java
similarity index 84%
rename from services/core/java/com/android/server/notification/TopicPriorityExtractor.java
rename to services/core/java/com/android/server/notification/PriorityExtractor.java
index 1df5c2b..6c76476 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PriorityExtractor.java
@@ -21,7 +21,7 @@
 /**
  * Determines if the given notification can bypass Do Not Disturb.
  */
-public class TopicPriorityExtractor implements NotificationSignalExtractor {
+public class PriorityExtractor implements NotificationSignalExtractor {
     private static final String TAG = "ImportantTopicExtractor";
     private static final boolean DBG = false;
 
@@ -42,9 +42,8 @@
             return null;
         }
 
-        final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
-                record.sbn.getUid(), record.sbn.getNotification().getTopic());
-        record.setPackagePriority(packagePriority);
+        record.setPackagePriority(
+                mConfig.getPriority(record.sbn.getPackageName(), record.sbn.getUid()));
 
         return null;
     }
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 9773474..b5cc2ef 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -15,30 +15,17 @@
  */
 package com.android.server.notification;
 
-import android.app.Notification;
-
-import java.util.List;
-
 public interface RankingConfig {
 
-    List<Notification.Topic> getTopics(String packageName, int uid);
+    int getPriority(String packageName, int uid);
 
-    int getPriority(String packageName, int uid, Notification.Topic topic);
+    void setPriority(String packageName, int uid, int priority);
 
-    void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
+    int getVisibilityOverride(String packageName, int uid);
 
-    int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+    void setVisibilityOverride(String packageName, int uid, int visibility);
 
-    void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
-            int visibility);
+    void setImportance(String packageName, int uid, int importance);
 
-    void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
-
-    int getImportance(String packageName, int uid, Notification.Topic topic);
-
-    boolean doesUserUseTopics(String packageName, int uid);
-
-    boolean hasBannedTopics(String packageName, int uid);
-
-    int getImportance(String packageName, int uid, String topicId);
+    int getImportance(String packageName, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 91eab10..fd96a78 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -20,14 +20,11 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 
-import com.android.internal.R;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -36,8 +33,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
-import java.util.Map;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -47,7 +42,6 @@
     private static final String TAG_RANKING = "ranking";
     private static final String TAG_PACKAGE = "package";
     private static final String ATT_VERSION = "version";
-    private static final String TAG_TOPIC = "topic";
 
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
@@ -141,8 +135,6 @@
             if (type == XmlPullParser.START_TAG) {
                 if (TAG_PACKAGE.equals(tag)) {
                     int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
-                    int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
-                    int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
                     String name = parser.getAttributeValue(null, ATT_NAME);
 
                     if (!TextUtils.isEmpty(name)) {
@@ -165,16 +157,8 @@
                             r = getOrCreateRecord(name, uid);
                         }
                         r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
-                        r.priority = priority;
-                        r.visibility = vis;
-
-                        // Migrate package level settings to the default topic.
-                        // Might be overwritten by parseTopics.
-                        Topic defaultTopic = r.topics.get(Notification.TOPIC_DEFAULT);
-                        defaultTopic.priority = priority;
-                        defaultTopic.visibility = vis;
-
-                        parseTopics(r, parser);
+                        r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
+                        r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
                     }
                 }
             }
@@ -182,42 +166,6 @@
         throw new IllegalStateException("Failed to reach END_DOCUMENT");
     }
 
-    public void parseTopics(Record r, XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        final int innerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (TAG_TOPIC.equals(tagName)) {
-                int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
-                int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
-                int importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
-                String id = parser.getAttributeValue(null, ATT_TOPIC_ID);
-                CharSequence label = parser.getAttributeValue(null, ATT_TOPIC_LABEL);
-
-                if (!TextUtils.isEmpty(id)) {
-                    Topic topic = new Topic(new Notification.Topic(id, label));
-
-                    if (priority != DEFAULT_PRIORITY) {
-                        topic.priority = priority;
-                    }
-                    if (vis != DEFAULT_VISIBILITY) {
-                        topic.visibility = vis;
-                    }
-                    if (importance != DEFAULT_IMPORTANCE) {
-                        topic.importance = importance;
-                    }
-                    r.topics.put(id, topic);
-                }
-            }
-        }
-    }
-
     private static String recordKey(String pkg, int uid) {
         return pkg + "|" + uid;
     }
@@ -229,7 +177,6 @@
             r = new Record();
             r.pkg = pkg;
             r.uid = uid;
-            r.topics.put(Notification.TOPIC_DEFAULT, new Topic(createDefaultTopic()));
             mRecords.put(key, r);
         }
         return r;
@@ -246,46 +193,31 @@
             if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
                 continue;
             }
-            out.startTag(null, TAG_PACKAGE);
-            out.attribute(null, ATT_NAME, r.pkg);
-            if (r.importance != DEFAULT_IMPORTANCE) {
-                out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
-            }
-            if (r.priority != DEFAULT_PRIORITY) {
-                out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
-            }
-            if (r.visibility != DEFAULT_VISIBILITY) {
-                out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
-            }
+            final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
+                    || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
+            if (hasNonDefaultSettings) {
+                out.startTag(null, TAG_PACKAGE);
+                out.attribute(null, ATT_NAME, r.pkg);
+                if (r.importance != DEFAULT_IMPORTANCE) {
+                    out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+                }
+                if (r.priority != DEFAULT_PRIORITY) {
+                    out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+                }
+                if (r.visibility != DEFAULT_VISIBILITY) {
+                    out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+                }
 
-            if (!forBackup) {
-                out.attribute(null, ATT_UID, Integer.toString(r.uid));
-            }
+                if (!forBackup) {
+                    out.attribute(null, ATT_UID, Integer.toString(r.uid));
+                }
 
-            writeTopicsXml(out, r);
-            out.endTag(null, TAG_PACKAGE);
+                out.endTag(null, TAG_PACKAGE);
+            }
         }
         out.endTag(null, TAG_RANKING);
     }
 
-    public void writeTopicsXml(XmlSerializer out, Record r) throws IOException {
-        for (Topic t : r.topics.values()) {
-            out.startTag(null, TAG_TOPIC);
-            out.attribute(null, ATT_TOPIC_ID, t.topic.getId());
-            out.attribute(null, ATT_TOPIC_LABEL, t.topic.getLabel().toString());
-            if (t.priority != DEFAULT_PRIORITY) {
-                out.attribute(null, ATT_PRIORITY, Integer.toString(t.priority));
-            }
-            if (t.visibility != DEFAULT_VISIBILITY) {
-                out.attribute(null, ATT_VISIBILITY, Integer.toString(t.visibility));
-            }
-            if (t.importance != DEFAULT_IMPORTANCE) {
-                out.attribute(null, ATT_IMPORTANCE, Integer.toString(t.importance));
-            }
-            out.endTag(null, TAG_TOPIC);
-        }
-    }
-
     private void updateConfig() {
         final int N = mSignalExtractors.length;
         for (int i = 0; i < N; i++) {
@@ -370,189 +302,62 @@
         }
     }
 
-    private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
-        final String val = parser.getAttributeValue(null, att);
-        return tryParseBool(val, defValue);
-    }
-
     private static boolean tryParseBool(String value, boolean defValue) {
         if (TextUtils.isEmpty(value)) return defValue;
         return Boolean.valueOf(value);
     }
 
+    /**
+     * Gets priority.
+     */
     @Override
-    public List<Notification.Topic> getTopics(String packageName, int uid) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        List<Notification.Topic> topics = new ArrayList<>();
-        for (Topic t : r.topics.values()) {
-            topics.add(t.topic);
-        }
-        return topics;
-    }
-
-    @Override
-    public boolean hasBannedTopics(String packageName, int uid) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        for (Topic t : r.topics.values()) {
-            if (t.importance == Ranking.IMPORTANCE_NONE) {
-                return true;
-            }
-        }
-        return false;
+    public int getPriority(String packageName, int uid) {
+        return getOrCreateRecord(packageName, uid).priority;
     }
 
     /**
-     * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
-     * priority of the app.
+     * Sets priority.
      */
     @Override
-    public int getPriority(String packageName, int uid, Notification.Topic topic) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        if (topic == null) {
-            return r.priority;
-        }
-        return getOrCreateTopic(r, topic).priority;
-    }
-
-    /**
-     * Sets priority. If a topic is given, sets the priority of that topic. If not,
-     * sets the default priority for all new topics that appear in the future, and resets
-     * the priority of all current topics.
-     */
-    @Override
-    public void setPriority(String packageName, int uid, Notification.Topic topic,
-            int priority) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        if (topic == null) {
-            r.priority = priority;
-            for (Topic t : r.topics.values()) {
-                t.priority = priority;
-            }
-        } else {
-            getOrCreateTopic(r, topic).priority = priority;
-        }
+    public void setPriority(String packageName, int uid, int priority) {
+        getOrCreateRecord(packageName, uid).priority = priority;
         updateConfig();
     }
 
     /**
-     * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
-     * override of the app.
+     * Gets visual override.
      */
     @Override
-    public int getVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        if (topic == null) {
-            return r.visibility;
-        }
-        return getOrCreateTopic(r, topic).visibility;
+    public int getVisibilityOverride(String packageName, int uid) {
+        return getOrCreateRecord(packageName, uid).visibility;
     }
 
     /**
-     * Sets visibility override. If a topic is given, sets the override of that topic. If not,
-     * sets the default override for all new topics that appear in the future, and resets
-     * the override of all current topics.
+     * Sets visibility override.
      */
     @Override
-    public void setVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
-        int visibility) {
-        final Record r = getOrCreateRecord(pkgName, uid);
-        if (topic == null) {
-            r.visibility = visibility;
-            for (Topic t : r.topics.values()) {
-                t.visibility = visibility;
-            }
-        } else {
-            getOrCreateTopic(r, topic).visibility = visibility;
-        }
+    public void setVisibilityOverride(String pkgName, int uid, int visibility) {
+        getOrCreateRecord(pkgName, uid).visibility = visibility;
         updateConfig();
     }
 
     /**
-     * Gets the importance of a topic. Unlike {@link #getImportance(String, int, String)}, does not
-     * create package or topic records if they don't exist.
+     * Gets importance.
      */
     @Override
-    public int getImportance(String packageName, int uid, String topicId) {
-        final String key = recordKey(packageName, uid);
-        Record r = mRecords.get(key);
-        if (r == null) {
-            return Ranking.IMPORTANCE_UNSPECIFIED;
-        }
-        Topic t = r.topics.get(topicId);
-        if (t == null) {
-            return Ranking.IMPORTANCE_UNSPECIFIED;
-        }
-        return t.importance;
+    public int getImportance(String packageName, int uid) {
+        return getOrCreateRecord(packageName, uid).importance;
     }
 
     /**
-     * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
-     * importance of the app.
+     * Sets importance.
      */
     @Override
-    public int getImportance(String packageName, int uid, Notification.Topic topic) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        if (topic == null) {
-            return r.importance;
-        }
-        return getOrCreateTopic(r, topic).importance;
-    }
-
-    /**
-     * Sets importance. If a topic is given, sets the importance of that topic. If not, sets the
-     * default importance for all new topics that appear in the future, and resets
-     * the importance of all current topics (unless the app is being blocked).
-     */
-    @Override
-    public void setImportance(String pkgName, int uid, Notification.Topic topic,
-            int importance) {
-        final Record r = getOrCreateRecord(pkgName, uid);
-        if (topic == null) {
-            r.importance = importance;
-            if (Ranking.IMPORTANCE_NONE != importance) {
-                for (Topic t : r.topics.values()) {
-                    t.importance = importance;
-                }
-            }
-        } else {
-            getOrCreateTopic(r, topic).importance = importance;
-        }
+    public void setImportance(String pkgName, int uid, int importance) {
+        getOrCreateRecord(pkgName, uid).importance = importance;
         updateConfig();
     }
 
-    @Override
-    public boolean doesUserUseTopics(String pkgName, int uid) {
-        final Record r = getOrCreateRecord(pkgName, uid);
-        for (Topic topic : r.topics.values()) {
-            if (topic.importance != Ranking.IMPORTANCE_UNSPECIFIED
-                    && r.importance != topic.importance)
-                return true;
-        }
-        return false;
-    }
-
-    private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
-        if (topic == null) {
-            topic = createDefaultTopic();
-        }
-        Topic t = r.topics.get(topic.getId());
-        if (t != null) {
-            return t;
-        } else {
-            t = new Topic(topic);
-            t.importance = r.importance;
-            t.priority = r.priority;
-            t.visibility = r.visibility;
-            r.topics.put(topic.getId(), t);
-            return t;
-        }
-    }
-
-    private Notification.Topic createDefaultTopic() {
-        return new Notification.Topic(Notification.TOPIC_DEFAULT,
-                mContext.getString(R.string.default_notification_topic_label));
-    }
-
     public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
         if (filter == null) {
             final int N = mSignalExtractors.length;
@@ -600,25 +405,6 @@
                     pw.print(Ranking.importanceToString(r.visibility));
                 }
                 pw.println();
-                for (Topic t : r.topics.values()) {
-                    pw.print(prefix);
-                    pw.print("  ");
-                    pw.print("  ");
-                    pw.print(t.topic.getId());
-                    if (t.priority != DEFAULT_PRIORITY) {
-                        pw.print(" priority=");
-                        pw.print(Notification.priorityToString(t.priority));
-                    }
-                    if (t.visibility != DEFAULT_VISIBILITY) {
-                        pw.print(" visibility=");
-                        pw.print(Notification.visibilityToString(t.visibility));
-                    }
-                    if (t.importance != DEFAULT_IMPORTANCE) {
-                        pw.print(" importance=");
-                        pw.print(Ranking.importanceToString(t.importance));
-                    }
-                    pw.println();
-                }
             }
         }
     }
@@ -657,17 +443,5 @@
         int importance = DEFAULT_IMPORTANCE;
         int priority = DEFAULT_PRIORITY;
         int visibility = DEFAULT_VISIBILITY;
-        Map<String, Topic> topics = new ArrayMap<>();
    }
-
-    private static class Topic {
-        Notification.Topic topic;
-        int priority = DEFAULT_PRIORITY;
-        int visibility = DEFAULT_VISIBILITY;
-        int importance = DEFAULT_IMPORTANCE;
-
-        public Topic(Notification.Topic topic) {
-            this.topic = topic;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
similarity index 79%
rename from services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
rename to services/core/java/com/android/server/notification/VisibilityExtractor.java
index eaa3ed3..2da2b2f 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -21,8 +21,8 @@
 /**
  * Determines if the given notification can display sensitive content on the lockscreen.
  */
-public class TopicVisibilityExtractor implements NotificationSignalExtractor {
-    private static final String TAG = "TopicVisibilityExtractor";
+public class VisibilityExtractor implements NotificationSignalExtractor {
+    private static final String TAG = "VisibilityExtractor";
     private static final boolean DBG = false;
 
     private RankingConfig mConfig;
@@ -42,10 +42,8 @@
             return null;
         }
 
-        final int packageVisibility = mConfig.getVisibilityOverride(
-                record.sbn.getPackageName(), record.sbn.getUid(),
-                record.sbn.getNotification().getTopic());
-        record.setPackageVisibilityOverride(packageVisibility);
+        record.setPackageVisibilityOverride(
+                mConfig.getVisibilityOverride(record.sbn.getPackageName(), record.sbn.getUid()));
 
         return null;
     }
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 31182fc..f1fe346 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -25,7 +25,6 @@
 import org.mockito.MockitoAnnotations;
 
 import android.app.Notification;
-import android.os.Handler;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.test.AndroidTestCase;
@@ -55,14 +54,13 @@
         UserHandle user = UserHandle.ALL;
 
         mHelper = new RankingHelper(getContext(), handler, mUsageStats,
-                new String[] {TopicImportanceExtractor.class.getName()});
+                new String[] {ImportanceExtractor.class.getName()});
 
         mNotiGroupGSortA = new Notification.Builder(getContext())
                 .setContentTitle("A")
                 .setGroup("G")
                 .setSortKey("A")
                 .setWhen(1205)
-                .setTopic(new Notification.Topic("A", "a"))
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
@@ -72,7 +70,6 @@
                 .setGroup("G")
                 .setSortKey("B")
                 .setWhen(1200)
-                .setTopic(new Notification.Topic("A", "a"))
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
@@ -80,7 +77,6 @@
         mNotiNoGroup = new Notification.Builder(getContext())
                 .setContentTitle("C")
                 .setWhen(1201)
-                .setTopic(new Notification.Topic("C", "c"))
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
@@ -88,7 +84,6 @@
         mNotiNoGroup2 = new Notification.Builder(getContext())
                 .setContentTitle("D")
                 .setWhen(1202)
-                .setTopic(new Notification.Topic("D", "d"))
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
@@ -97,7 +92,6 @@
                 .setContentTitle("E")
                 .setWhen(1201)
                 .setSortKey("A")
-                .setTopic(new Notification.Topic("E", "e"))
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
@@ -152,26 +146,4 @@
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
         mHelper.sort(notificationList);
     }
-
-    @SmallTest
-    public void testTopicImportanceExtractor() throws Exception {
-        mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
-        // There is no B. There never was a b. Moving on...
-        mHelper.setImportance("package", 0, new Notification.Topic("C", "c"), IMPORTANCE_HIGH);
-        mHelper.setImportance("package", 0, new Notification.Topic("D", "d"), IMPORTANCE_LOW);
-        // watch out: different package.
-        mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
-
-        TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
-        validator.process(mRecordGroupGSortA);
-        validator.process(mRecordGroupGSortB);
-        validator.process(mRecordNoGroup);
-        validator.process(mRecordNoGroup2);
-        validator.process(mRecordNoGroupSortA);
-        assertTrue(mRecordGroupGSortA.getTopicImportance() == IMPORTANCE_MAX);
-        assertTrue(mRecordGroupGSortB.getTopicImportance() == IMPORTANCE_MAX);
-        assertTrue(mRecordNoGroup.getTopicImportance() == IMPORTANCE_HIGH);
-        assertTrue(mRecordNoGroup2.getTopicImportance() == IMPORTANCE_LOW);
-        assertTrue(mRecordNoGroupSortA.getTopicImportance() == IMPORTANCE_UNSPECIFIED);
-    }
 }
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 46de201..9ac4dbf 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -162,78 +162,6 @@
             }
         },
 
-        new Test("with topic Hello") {
-            public void run() {
-                Notification.BigTextStyle bigText = new Notification.BigTextStyle();
-                bigText.bigText("FgBHreherhethethethe\ntwetwrterter\netetweterteryetry");
-                Notification n = new Notification.Builder(NotificationTestList.this)
-                        .setSmallIcon(R.drawable.icon1)
-                        .setStyle(bigText)
-                        .setWhen(mActivityCreateTime)
-                        .setContentTitle("hihi")
-                        .setContentText("This is a notification!!!")
-                        .setContentIntent(makeIntent2())
-                        .setTopic(new Notification.Topic("hello", "Hello"))
-                        .build();
-
-                mNM.notify(70, n);
-            }
-        },
-
-        new Test("with topic GoodBye") {
-            public void run() {
-                Notification.BigPictureStyle picture = new Notification.BigPictureStyle();
-                picture.bigPicture(BitmapFactory.decodeResource(getResources(),
-                        R.id.large_icon_pineapple2));
-                Notification n = new Notification.Builder(NotificationTestList.this)
-                        .setSmallIcon(R.drawable.icon1)
-                        .setWhen(mActivityCreateTime)
-                        .setContentTitle("byebye")
-                        .setContentText("This is a notification!!!")
-                        .setContentIntent(makeIntent2())
-                        .setTopic(new Notification.Topic("bye", "Goodbye"))
-                        .setStyle(picture)
-                        .build();
-
-                mNM.notify(71, n);
-            }
-        },
-        new Test("with topic Bananas") {
-            public void run() {
-                Notification.BigTextStyle bigText = new Notification.BigTextStyle();
-                bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
-                Notification n = new Notification.Builder(NotificationTestList.this)
-                        .setSmallIcon(R.drawable.icon1)
-                        .setStyle(bigText)
-                        .setWhen(mActivityCreateTime)
-                        .setContentTitle("bananananana")
-                        .setContentText("This is a banana!!!")
-                        .setContentIntent(makeIntent2())
-                        .setTopic(new Notification.Topic("bananas", "Bananas"))
-                        .build();
-
-                mNM.notify(72, n);
-            }
-        },
-
-            new Test("with delete intent") {
-                public void run() {
-                    Notification.BigTextStyle bigText = new Notification.BigTextStyle();
-                    bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
-                    Notification n = new Notification.Builder(NotificationTestList.this)
-                            .setSmallIcon(R.drawable.icon1)
-                            .setStyle(bigText)
-                            .setWhen(mActivityCreateTime)
-                            .setContentTitle("bananananana")
-                            .setContentText("This is a banana!!!")
-                            .setTopic(new Notification.Topic("bananas", "Bananas"))
-                            .setDeleteIntent(makeIntent2())
-                            .build();
-
-                    mNM.notify(73, n);
-                }
-            },
-
             new Test("Is blocked?") {
                 public void run() {
                     Toast.makeText(NotificationTestList.this,
@@ -242,18 +170,10 @@
                 }
             },
 
-            new Test("Topic banana importance?") {
+            new Test("importance?") {
                 public void run() {
                     Toast.makeText(NotificationTestList.this,
-                            "bananas importance? " + mNM.getImportance("bananas"),
-                            Toast.LENGTH_LONG).show();
-                }
-            },
-
-            new Test("Topic garbage importance?") {
-                public void run() {
-                    Toast.makeText(NotificationTestList.this,
-                            "garbage importance? " + mNM.getImportance("garbage"),
+                            "importance? " + mNM.getImportance(),
                             Toast.LENGTH_LONG).show();
                 }
             },
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 94f3f54..4901f72 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -45,10 +45,4 @@
     public static void dispatchOnPreDraw(View view) {
         view.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
     }
-
-    public static void detachFromWindow(View view) {
-        if (view != null) {
-            view.dispatchDetachedFromWindow();
-        }
-    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java
deleted file mode 100644
index 51b42a6..0000000
--- a/tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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.view;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate used to provide new implementation of a select few methods of
- * {@link ViewRootImpl.RunQueue}
- *
- * Through the layoutlib_create tool, the original  methods of ViewRootImpl.RunQueue have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- */
-public class ViewRootImpl_RunQueue_Delegate {
-
-    @LayoutlibDelegate
-    /*package*/ static void postDelayed(ViewRootImpl.RunQueue thisQueue, Runnable action, long
-            delayMillis) {
-        // The actual RunQueue is never run and therefore never cleared. This method avoids
-        // runnables to be added to the RunQueue so they do not leak resources.
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index fea633e..2ac212c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -208,9 +208,6 @@
 
     @Override
     public void dispose() {
-        if (mSession != null) {
-            mSession.dispose();
-        }
     }
 
     /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 99af226..ec50cfe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -1396,21 +1396,4 @@
     public RenderSession getSession() {
         return mScene;
     }
-
-    public void dispose() {
-        AttachInfo_Accessor.detachFromWindow(mViewRoot);
-        if (mCanvas != null) {
-            mCanvas.release();
-            mCanvas = null;
-        }
-        if (mViewInfoList != null) {
-            mViewInfoList.clear();
-        }
-        if (mSystemViewInfoList != null) {
-            mSystemViewInfoList.clear();
-        }
-        mImage = null;
-        mViewRoot = null;
-        mContentRoot = null;
-    }
 }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 6b23da7..fe16a3e 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -291,6 +291,7 @@
     @Test
     public void testActivity() throws ClassNotFoundException {
         renderAndVerify("activity.xml", "activity.png");
+
     }
 
     /** Test allwidgets.xml */
@@ -430,8 +431,6 @@
             ImageUtils.requireSimilar(goldenImagePath, session.getImage());
         } catch (IOException e) {
             getLogger().error(e, e.getMessage());
-        } finally {
-            session.dispose();
         }
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 1f4341c..9e390f6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -183,7 +183,6 @@
         "android.view.View#getWindowToken",
         "android.view.View#isInEditMode",
         "android.view.ViewRootImpl#isInTouchMode",
-        "android.view.ViewRootImpl$RunQueue#postDelayed",
         "android.view.WindowManagerGlobal#getWindowManagerService",
         "android.view.inputmethod.InputMethodManager#getInstance",
         "android.view.MenuInflater#registerMenu",
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 31da670..ed12bdf 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -331,6 +331,7 @@
      */
     public static class InformationElement {
         public static final int EID_SSID = 0;
+        public static final int EID_TIM = 5;
         public static final int EID_BSS_LOAD = 11;
         public static final int EID_RSN = 48;
         public static final int EID_HT_OPERATION = 61;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index cce8386..ddd8f43 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -403,6 +403,15 @@
 
     /**
      * @hide
+     * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
+     * This value is populated from scan results that contain Beacon Frames, which are infrequent.
+     * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
+     * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
+     */
+    public int dtimInterval = 0;
+
+    /**
+     * @hide
      * Uid of app creating the configuration
      */
     @SystemApi
@@ -1298,6 +1307,7 @@
         lastUpdateUid = -1;
         creatorUid = -1;
         shared = true;
+        dtimInterval = 0;
     }
 
     /**
@@ -2044,4 +2054,4 @@
         config.allowedKeyManagement.set(in.readInt());
         return config;
     }
-}
\ No newline at end of file
+}