Merge changes from topic 'xc_remove_shelf'

* changes:
  sysui: remove shelf
  DO NOT MERGE sysui: remove shelf
diff --git a/Android.mk b/Android.mk
index 53e892f..3f44d62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -430,6 +430,14 @@
 	core/java/android/service/quicksettings/IQSService.aidl \
 	core/java/android/service/quicksettings/IQSTileService.aidl \
 
+# The following are native binders that need to go with the native component
+# at system/update_engine/binder_bindings/. Use relative path to refer to them.
+LOCAL_SRC_FILES += \
+	../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
+	../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
+
+LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
+
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
 LOCAL_AIDL_INCLUDES += \
       $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 368b8ef..3288cd9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,13 +48,12 @@
     boolean areNotificationsEnabledForPackage(String pkg, int uid);
 
     ParceledListSlice getTopics(String pkg, int uid);
-    void setTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
-    int getTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
-    void setTopicPriority(String pkg, int uid, in Notification.Topic topic, int priority);
-    int getTopicPriority(String pkg, int uid, in Notification.Topic topic);
-    void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance);
-    int getTopicImportance(String pkg, int uid, in Notification.Topic topic);
-    void setAppImportance(String pkg, int uid, int importance);
+    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);
     boolean doesAppUseTopics(String pkg, int uid);
 
     // TODO: Remove this when callers have been migrated to the equivalent
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 74cb0f6..9cd7d05 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -104,8 +104,6 @@
     void getActivityEnergyInfoFromController();
     BluetoothActivityEnergyInfo reportActivityInfo();
 
-    // For dumpsys support
-    void dump(in ParcelFileDescriptor fd);
     void onLeServiceUp();
     void onBrEdrDown();
 }
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 777baab..66181e0 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.util.Objects;
+
 /**
  * This class represents a print job from the perspective of an
  * application. It contains behavior methods for performing operations
@@ -30,11 +32,11 @@
  */
 public final class PrintJob {
 
-    private final PrintManager mPrintManager;
+    private final @NonNull PrintManager mPrintManager;
 
-    private PrintJobInfo mCachedInfo;
+    private @NonNull PrintJobInfo mCachedInfo;
 
-    PrintJob(PrintJobInfo info, PrintManager printManager) {
+    PrintJob(@NonNull PrintJobInfo info, @NonNull PrintManager printManager) {
         mCachedInfo = info;
         mPrintManager = printManager;
     }
@@ -44,7 +46,7 @@
      *
      * @return The id.
      */
-    public @NonNull PrintJobId getId() {
+    public @Nullable PrintJobId getId() {
         return mCachedInfo.getId();
     }
 
@@ -58,7 +60,7 @@
      *
      * @return The print job info.
      */
-    public @Nullable PrintJobInfo getInfo() {
+    public @NonNull PrintJobInfo getInfo() {
         if (isInImmutableState()) {
             return mCachedInfo;
         }
@@ -193,11 +195,17 @@
             return false;
         }
         PrintJob other = (PrintJob) obj;
-        return mCachedInfo.getId().equals(other.mCachedInfo.getId());
+        return Objects.equals(mCachedInfo.getId(), other.mCachedInfo.getId());
     }
 
     @Override
     public int hashCode() {
-        return mCachedInfo.getId().hashCode();
+        PrintJobId printJobId = mCachedInfo.getId();
+
+        if (printJobId == null) {
+            return 0;
+        } else {
+            return printJobId.hashCode();
+        }
     }
 }
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
index a2ee02b..186ae9b 100644
--- a/core/java/android/print/PrintJobId.java
+++ b/core/java/android/print/PrintJobId.java
@@ -19,7 +19,8 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
 
 import java.util.UUID;
 
@@ -27,7 +28,7 @@
  * This class represents the id of a print job.
  */
 public final class PrintJobId implements Parcelable {
-    private final String mValue;
+    private final @NonNull String mValue;
 
     /**
      * Creates a new instance.
@@ -45,7 +46,7 @@
      *
      * @hide
      */
-    public PrintJobId(String value) {
+    public PrintJobId(@NonNull String value) {
         mValue = value;
     }
 
@@ -53,7 +54,7 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+        result = prime * result + mValue.hashCode();
         return result;
     }
 
@@ -69,7 +70,7 @@
             return false;
         }
         PrintJobId other = (PrintJobId) obj;
-        if (!TextUtils.equals(mValue, other.mValue)) {
+        if (!mValue.equals(other.mValue)) {
             return false;
         }
         return true;
@@ -104,7 +105,7 @@
      *
      * @hide
      */
-    public static PrintJobId unflattenFromString(String string) {
+    public static @NonNull PrintJobId unflattenFromString(@NonNull String string) {
         return new PrintJobId(string);
     }
 
@@ -112,7 +113,7 @@
             new Parcelable.Creator<PrintJobId>() {
         @Override
         public PrintJobId createFromParcel(Parcel parcel) {
-            return new PrintJobId(parcel.readString());
+            return new PrintJobId(Preconditions.checkNotNull(parcel.readString()));
         }
 
         @Override
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 21836b3..7e3a72f 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -244,7 +244,7 @@
      *
      * @return The id.
      */
-    public @NonNull PrintJobId getId() {
+    public @Nullable PrintJobId getId() {
         return mId;
     }
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2f2c5e4..a276854 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4185,4 +4185,9 @@
     <string name="suspended_package_title">%1$s disabled</string>
     <!-- Message for dialog displayed when a packge is suspended by device admin. [CHAR LIMIT=NONE] -->
     <string name="suspended_package_message">Disabled by %1$s administrator. Contact them to learn more.</string>
+
+    <!-- Notification title shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+    <string name="new_sms_notification_title">You have new messages</string>
+    <!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+    <string name="new_sms_notification_content">Open SMS app to view</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1f2c6e1..e59c935 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2499,4 +2499,8 @@
   <java-symbol type="string" name="work_mode_turn_on" />
   <java-symbol type="string" name="suspended_package_title" />
   <java-symbol type="string" name="suspended_package_message" />
+
+  <!-- New SMS notification while phone is locked. -->
+  <java-symbol type="string" name="new_sms_notification_title" />
+  <java-symbol type="string" name="new_sms_notification_content" />
 </resources>
diff --git a/libs/hwui/BufferPool.h b/libs/hwui/BufferPool.h
index 9bda233..005b399 100644
--- a/libs/hwui/BufferPool.h
+++ b/libs/hwui/BufferPool.h
@@ -16,8 +16,9 @@
 
 #pragma once
 
-#include <utils/RefBase.h>
-#include <utils/Log.h>
+#include "utils/RefBase.h"
+#include "utils/Log.h"
+#include "utils/Macros.h"
 
 #include <atomic>
 #include <stdint.h>
@@ -37,6 +38,7 @@
 class BufferPool : public VirtualLightRefBase {
 public:
     class Buffer {
+        PREVENT_COPY_AND_ASSIGN(Buffer);
     public:
         int64_t* getBuffer() { return mBuffer.get(); }
         size_t getSize() { return mSize; }
@@ -57,14 +59,17 @@
             return refs - 1;
         }
 
+        bool isUniqueRef() {
+            return mRefs.load() == 1;
+        }
+
     private:
         friend class BufferPool;
 
-        Buffer(BufferPool* pool, size_t size) {
+        Buffer(BufferPool* pool, size_t size) : mRefs(1) {
             mSize = size;
             mBuffer.reset(new int64_t[size]);
             mPool = pool;
-            mRefs++;
         }
 
         void setPool(BufferPool* pool) {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 3e37a05..a457212 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -33,6 +33,15 @@
 FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
         uint32_t viewportWidth, uint32_t viewportHeight,
         const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
+        : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightCenter,
+                Rect(0, 0, 0, 0)) {
+}
+
+
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+        uint32_t viewportWidth, uint32_t viewportHeight,
+        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+        const Rect &contentDrawBounds)
         : mCanvasState(*this) {
     ATRACE_NAME("prepare drawing commands");
 
@@ -72,14 +81,56 @@
         }
     }
 
-    // Defer Fbo0
+    // It there are multiple render nodes, they are laid out as follows:
+    // #0 - backdrop (content + caption)
+    // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
+    // #2 - additional overlay nodes
+    // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
+    // resizing however it might become partially visible. The following render loop will crop the
+    // backdrop against the content and draw the remaining part of it. It will then draw the content
+    // cropped to the backdrop (since that indicates a shrinking of the window).
+    //
+    // Additional nodes will be drawn on top with no particular clipping semantics.
+
+    // The bounds of the backdrop against which the content should be clipped.
+    Rect backdropBounds = contentDrawBounds;
+    // Usually the contents bounds should be mContentDrawBounds - however - we will
+    // move it towards the fixed edge to give it a more stable appearance (for the moment).
+    // If there is no content bounds we ignore the layering as stated above and start with 2.
+    int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
+
     for (const sp<RenderNode>& node : nodes) {
         if (node->nothingToDraw()) continue;
         node->computeOrdering();
-
         int count = mCanvasState.save(SaveFlags::MatrixClip);
+
+        if (layer == 0) {
+            const RenderProperties& properties = node->properties();
+            Rect targetBounds(properties.getLeft(), properties.getTop(),
+                              properties.getRight(), properties.getBottom());
+            // Move the content bounds towards the fixed corner of the backdrop.
+            const int x = targetBounds.left;
+            const int y = targetBounds.top;
+            // Remember the intersection of the target bounds and the intersection bounds against
+            // which we have to crop the content.
+            backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
+            backdropBounds.doIntersect(targetBounds);
+        } else if (layer == 1) {
+            // We shift and clip the content to match its final location in the window.
+            const float left = contentDrawBounds.left;
+            const float top = contentDrawBounds.top;
+            const float dx = backdropBounds.left - left;
+            const float dy = backdropBounds.top - top;
+            const float width = backdropBounds.getWidth();
+            const float height = backdropBounds.getHeight();
+            mCanvasState.translate(dx, dy);
+            // It gets cropped against the bounds of the backdrop to stay inside.
+            mCanvasState.clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op);
+        }
+
         deferNodePropsAndOps(*node);
         mCanvasState.restoreToCount(count);
+        layer++;
     }
 }
 
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 4fd39be..dea9934 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -59,6 +59,11 @@
             uint32_t viewportWidth, uint32_t viewportHeight,
             const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
 
+    FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+            uint32_t viewportWidth, uint32_t viewportHeight,
+            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+            const Rect &contentDrawBounds);
+
     virtual ~FrameBuilder() {}
 
     /**
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 7148c4b..e7cf3ec 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -345,7 +345,7 @@
 
 #if HWUI_NEW_OPS
     FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
-            mRenderNodes, mLightCenter);
+            mRenderNodes, mLightCenter, mContentDrawBounds);
     mLayerUpdateQueue.clear();
     BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
             mOpaque, mLightInfo);
diff --git a/libs/hwui/tests/unit/BufferPoolTests.cpp b/libs/hwui/tests/unit/BufferPoolTests.cpp
index 09bd302..44e6d3a 100644
--- a/libs/hwui/tests/unit/BufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/BufferPoolTests.cpp
@@ -36,6 +36,7 @@
             ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
             acquiredBuffers[i] = pool->acquire();
             ASSERT_NE(nullptr, acquiredBuffers[i]);
+            ASSERT_TRUE(acquiredBuffers[i]->isUniqueRef());
         }
 
         for (size_t i = 0; i < bufferCount; i++) {
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index b75724c..618df14 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -215,7 +215,8 @@
             << "Expect number of ops = 2 * loop count";
 }
 
-TEST(FrameBuilder, clippedMerging) {
+// TODO: Disabled due to b/26793764
+TEST(FrameBuilder, DISABLED_clippedMerging) {
     class ClippedMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index a08e029..b0331be 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -17,7 +17,7 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:layout_margin="@dimen/grid_item_margin"
     android:background="@color/item_doc_background"
     android:elevation="5dp"
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 811adda..743df99 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -1003,7 +1003,9 @@
         if (currMediaSize == null) {
             attributes.setMediaSize(defaults.getMediaSize());
         } else {
-            boolean foundCurrentMediaSize = false;
+            MediaSize newMediaSize = null;
+            boolean isPortrait = currMediaSize.isPortrait();
+
             // Try to find the current media size in the capabilities as
             // it may be in a different orientation.
             MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
@@ -1011,14 +1013,21 @@
             for (int i = 0; i < mediaSizeCount; i++) {
                 MediaSize mediaSize = sortedMediaSizes.get(i);
                 if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
-                    attributes.setMediaSize(currMediaSize);
-                    foundCurrentMediaSize = true;
+                    newMediaSize = mediaSize;
                     break;
                 }
             }
             // If we did not find the current media size fall back to default.
-            if (!foundCurrentMediaSize) {
-                attributes.setMediaSize(defaults.getMediaSize());
+            if (newMediaSize == null) {
+                newMediaSize = defaults.getMediaSize();
+            }
+
+            if (newMediaSize != null) {
+                if (isPortrait) {
+                    attributes.setMediaSize(newMediaSize.asPortrait());
+                } else {
+                    attributes.setMediaSize(newMediaSize.asLandscape());
+                }
             }
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 58a477e..eaa563d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -38,14 +39,39 @@
 
     private static final String TAG = "SuggestionParser";
 
+    // If defined, only returns this suggestion if the feature is supported.
+    public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
+
+    /**
+     * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
+     * For instance:
+     * 0,10
+     * Will appear immediately, but if the user removes it, it will come back after 10 days.
+     *
+     * Another example:
+     * 10,30
+     * Will only show up after 10 days, and then again after 30.
+     */
+    public static final String META_DATA_DISMISS_CONTROL = "com.android.settings.dismiss";
+
+    // Shared prefs keys for storing dismissed state.
+    // Index into current dismissed state.
+    private static final String DISMISS_INDEX = "_dismiss_index";
+    private static final String SETUP_TIME = "_setup_time";
+    private static final String IS_DISMISSED = "_is_dismissed";
+
+    private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
+
     private final Context mContext;
     private final List<SuggestionCategory> mSuggestionList;
     private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+    private final SharedPreferences mSharedPrefs;
 
-    public SuggestionParser(Context context, int orderXml) {
+    public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
         mContext = context;
         mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
                 .parse(orderXml);
+        mSharedPrefs = sharedPrefs;
     }
 
     public List<Tile> getSuggestions() {
@@ -57,6 +83,23 @@
         return suggestions;
     }
 
+    /**
+     * Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
+     * be disabled.
+     */
+    public boolean dismissSuggestion(Tile suggestion) {
+        String keyBase = suggestion.intent.getComponent().flattenToShortString();
+        int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+        String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+        if (dismissControl == null || parseDismissString(dismissControl).length == index) {
+            return true;
+        }
+        mSharedPrefs.edit()
+                .putBoolean(keyBase + IS_DISMISSED, true)
+                .commit();
+        return false;
+    }
+
     private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
         int countBefore = suggestions.size();
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -66,6 +109,11 @@
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
                 addCache, null, suggestions, true, false);
+        for (int i = countBefore; i < suggestions.size(); i++) {
+            if (!isAvailable(suggestions.get(i)) || isDismissed(suggestions.get(i))) {
+                suggestions.remove(i--);
+            }
+        }
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
             // priority.
@@ -80,6 +128,58 @@
         }
     }
 
+    private boolean isAvailable(Tile suggestion) {
+        String featureRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
+        if (featureRequired != null) {
+            return mContext.getPackageManager().hasSystemFeature(featureRequired);
+        }
+        return true;
+    }
+
+    private boolean isDismissed(Tile suggestion) {
+        String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+        if (dismissControl == null) {
+            return false;
+        }
+        String keyBase = suggestion.intent.getComponent().flattenToShortString();
+        if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
+            mSharedPrefs.edit()
+                    .putLong(keyBase + SETUP_TIME, System.currentTimeMillis())
+                    .commit();
+        }
+        // Default to dismissed, so that we can have suggestions that only first appear after
+        // some number of days.
+        if (!mSharedPrefs.getBoolean(keyBase + IS_DISMISSED, true)) {
+            return false;
+        }
+        int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+        int currentDismiss = parseDismissString(dismissControl)[index];
+        long time = getEndTime(mSharedPrefs.getLong(keyBase + SETUP_TIME, 0), currentDismiss);
+        if (System.currentTimeMillis() >= time) {
+            // Dismiss timeout has passed, undismiss it.
+            mSharedPrefs.edit()
+                    .putBoolean(keyBase + IS_DISMISSED, false)
+                    .putInt(keyBase + DISMISS_INDEX, index + 1)
+                    .commit();
+            return false;
+        }
+        return true;
+    }
+
+    private long getEndTime(long startTime, int daysDelay) {
+        long days = daysDelay * MILLIS_IN_DAY;
+        return startTime + days;
+    }
+
+    private int[] parseDismissString(String dismissControl) {
+        String[] dismissStrs = dismissControl.split(",");
+        int[] dismisses = new int[dismissStrs.length];
+        for (int i = 0; i < dismissStrs.length; i++) {
+            dismisses[i] = Integer.parseInt(dismissStrs[i]);
+        }
+        return dismisses;
+    }
+
     private static class SuggestionCategory {
         public String category;
         public String pkg;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index e4cd7d9..5abd1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -206,13 +206,8 @@
     void saveImportance(final StatusBarNotification sbn) {
         int progress = mSeekBar.getProgress();
         try {
-            if (mApplyToTopic.isChecked()) {
-                mINotificationManager.setTopicImportance(sbn.getPackageName(), sbn.getUid(), mTopic,
-                        progress);
-            } else {
-                mINotificationManager.setAppImportance(
-                        sbn.getPackageName(), sbn.getUid(), progress);
-            }
+            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
+                    mApplyToTopic.isChecked() ? mTopic : null, progress);
         } catch (RemoteException e) {
             // :(
         }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index d63dd0c..46198b0 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1920,7 +1920,9 @@
                 synchronized (mBackupParticipants) {
                     if (replacing) {
                         // This is the package-replaced case; we just remove the entry
-                        // under the old uid and fall through to re-add.
+                        // under the old uid and fall through to re-add.  If an app
+                        // just added key/value backup participation, this picks it up
+                        // as a known participant.
                         removePackageParticipantsLocked(pkgList, uid);
                     }
                     addPackageParticipantsLocked(pkgList);
@@ -1933,6 +1935,14 @@
                         if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob(0);
+                        } else {
+                            // The app might have just transitioned out of full-data into
+                            // doing key/value backups, or might have just disabled backups
+                            // entirely.  Make sure it is no longer in the full-data queue.
+                            synchronized (mQueueLock) {
+                                dequeueFullBackupLocked(packageName);
+                            }
+                            writeFullBackupScheduleAsync();
                         }
 
                         // Transport maintenance: rebind to known existing transports that have
@@ -1964,6 +1974,9 @@
                 if (replacing) {
                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                 } else {
+                    // Outright removal.  In the full-data case, the app will be dropped
+                    // from the queue when its (now obsolete) name comes up again for
+                    // backup.
                     synchronized (mBackupParticipants) {
                         removePackageParticipantsLocked(pkgList, uid);
                     }
@@ -4190,11 +4203,21 @@
                         // as well as any explicit mention of the 'special' shared-storage agent
                         // package (we handle that one at the end).
                         if (MORE_DEBUG) {
-                            Slog.d(TAG, "Ignoring not eligible package " + pkg);
+                            Slog.d(TAG, "Ignoring ineligible package " + pkg);
                         }
                         sendBackupOnResult(mBackupObserver, pkg,
                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                         continue;
+                    } else if (!appGetsFullBackup(info)) {
+                        // Cull any packages that are found in the queue but now aren't supposed
+                        // to get full-data backup operations.
+                        if (MORE_DEBUG) {
+                            Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+                                    + pkg);
+                        }
+                        sendBackupOnResult(mBackupObserver, pkg,
+                                BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                        continue;
                     } else if (appIsStopped(info.applicationInfo)) {
                         // Cull any packages in the 'stopped' state: they've either just been
                         // installed or have explicitly been force-stopped by the user.  In both
@@ -4592,21 +4615,28 @@
     }
 
     /**
+     * Remove a package from the full-data queue.
+     */
+    void dequeueFullBackupLocked(String packageName) {
+        final int N = mFullBackupQueue.size();
+        for (int i = N-1; i >= 0; i--) {
+            final FullBackupEntry e = mFullBackupQueue.get(i);
+            if (packageName.equals(e.packageName)) {
+                mFullBackupQueue.remove(i);
+            }
+        }
+    }
+
+    /**
      * Enqueue full backup for the given app, with a note about when it last ran.
      */
     void enqueueFullBackup(String packageName, long lastBackedUp) {
         FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
         synchronized (mQueueLock) {
-            int N = mFullBackupQueue.size();
             // First, sanity check that we aren't adding a duplicate.  Slow but
             // straightforward; we'll have at most on the order of a few hundred
             // items in this list.
-            for (int i = N-1; i >= 0; i--) {
-                final FullBackupEntry e = mFullBackupQueue.get(i);
-                if (packageName.equals(e.packageName)) {
-                    mFullBackupQueue.remove(i);
-                }
-            }
+            dequeueFullBackupLocked(packageName);
 
             // This is also slow but easy for modest numbers of apps: work backwards
             // from the end of the queue until we find an item whose last backup
@@ -4700,21 +4730,24 @@
                 return false;
             }
 
-            if (mFullBackupQueue.size() == 0) {
-                // no work to do so just bow out
-                if (DEBUG) {
-                    Slog.i(TAG, "Backup queue empty; doing nothing");
-                }
-                return false;
-            }
-
-            // At this point we know that we have work to do, but possibly not right now.
+            // At this point we think that we have work to do, but possibly not right now.
             // Any exit without actually running backups will also require that we
             // reschedule the job.
             boolean runBackup = true;
             boolean headBusy;
 
             do {
+                // Recheck each time, because culling due to ineligibility may
+                // have emptied the queue.
+                if (mFullBackupQueue.size() == 0) {
+                    // no work to do so just bow out
+                    if (DEBUG) {
+                        Slog.i(TAG, "Backup queue empty; doing nothing");
+                    }
+                    runBackup = false;
+                    break;
+                }
+
                 headBusy = false;
 
                 if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
@@ -4744,6 +4777,19 @@
 
                     try {
                         PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
+                        if (!appGetsFullBackup(appInfo)) {
+                            // The head app isn't supposed to get full-data backups [any more];
+                            // so we cull it and force a loop around to consider the new head
+                            // app.
+                            if (MORE_DEBUG) {
+                                Slog.i(TAG, "Culling package " + entry.packageName
+                                        + " in full-backup queue but not eligible");
+                            }
+                            mFullBackupQueue.remove(0);
+                            headBusy = true; // force the while() condition
+                            continue;
+                        }
+
                         headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
 
                         if (headBusy) {
@@ -4762,7 +4808,6 @@
                             enqueueFullBackup(entry.packageName,
                                     nextEligible - MIN_FULL_BACKUP_INTERVAL);
                         }
-
                     } catch (NameNotFoundException nnf) {
                         // So, we think we want to back this up, but it turns out the package
                         // in question is no longer installed.  We want to drop it from the
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c1a082b..499b706 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -114,13 +114,6 @@
     private static final int SERVICE_IBLUETOOTH = 1;
     private static final int SERVICE_IBLUETOOTHGATT = 2;
 
-    private static final String[] DEVICE_TYPE_NAMES = new String[] {
-            "???",
-            "BR/EDR",
-            "LE",
-            "DUAL"
-        };
-
     private final Context mContext;
     private static int mBleAppCount = 0;
 
@@ -131,6 +124,7 @@
     private final ContentResolver mContentResolver;
     private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
     private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
+    private IBinder mBluetoothBinder;
     private IBluetooth mBluetooth;
     private IBluetoothGatt mBluetoothGatt;
     private boolean mBinding;
@@ -242,6 +236,7 @@
 
         mContext = context;
         mBluetooth = null;
+        mBluetoothBinder = null;
         mBluetoothGatt = null;
         mBinding = false;
         mUnbinding = false;
@@ -678,6 +673,7 @@
                 }
 
                 if (DBG) Log.d(TAG, "Sending unbind request.");
+                mBluetoothBinder = null;
                 mBluetooth = null;
                 //Unbind
                 mContext.unbindService(mConnection);
@@ -1166,6 +1162,7 @@
                         mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
 
                         mBinding = false;
+                        mBluetoothBinder = service;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
                         try {
@@ -1674,44 +1671,15 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        writer.println("Bluetooth Status");
-        writer.println("  enabled: " + mEnable);
-        writer.println("  state: " + mState);
-        writer.println("  address: " + mAddress);
-        writer.println("  name: " + mName + "\n");
-        writer.flush();
-
-        if (mBluetooth == null) {
-            writer.println("Bluetooth Service not connected");
-        } else {
-            ParcelFileDescriptor pfd = null;
-            try {
-                writer.println("Bonded devices:");
-                for (BluetoothDevice device : mBluetooth.getBondedDevices()) {
-                    writer.println("  " + device.getAddress() +
-                            " [" + DEVICE_TYPE_NAMES[device.getType()] + "] " +
-                            device.getName());
-                }
-                writer.flush();
-
-                pfd = ParcelFileDescriptor.dup(fd);
-                mBluetooth.dump(pfd);
-            } catch (RemoteException re) {
-                writer.println("RemoteException while calling Bluetooth Service");
-            } catch (IOException ioe) {
-                writer.println("IOException attempting to dup() fd");
-            } finally {
-                if (pfd != null) {
-                    try {
-                        pfd.close();
-                    } catch (IOException ioe) {
-                        writer.println("IOException attempting to close() fd");
-                    }
-                }
-            }
+    public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
+      if (mBluetoothBinder == null) {
+        writer.println("Bluetooth Service not connected");
+      } else {
+        try {
+          mBluetoothBinder.dump(fd, args);
+        } catch (RemoteException re) {
+          writer.println("RemoteException while calling Bluetooth Service");
         }
+      }
     }
 }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index dd19c6a..95f5734 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -186,7 +186,6 @@
 
     private final Handler mFgHandler;
     private final Handler mDaemonHandler;
-    private final PhoneStateListener mPhoneStateListener;
 
     private IBatteryStats mBatteryStats;
 
@@ -283,22 +282,6 @@
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
-        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                mDaemonHandler.getLooper()) {
-            @Override
-            public void onDataConnectionRealTimeInfoChanged(
-                    DataConnectionRealTimeInfo dcRtInfo) {
-                if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
-                notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
-                        dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
-            }
-        };
-        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        if (tm != null) {
-            tm.listen(mPhoneStateListener,
-                    PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
-        }
-
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
     }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 19a4851..9ee8e773 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,7 +34,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CellLocation;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.SubscriptionManager;
@@ -179,8 +178,6 @@
 
     private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
-    private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
-
     private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
 
     private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -624,13 +621,6 @@
                             remove(r.binder);
                         }
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
-                        try {
-                            r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
                     if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
                         try {
                             r.callback.onPreciseCallStateChanged(mPreciseCallState);
@@ -921,31 +911,6 @@
         }
     }
 
-    public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
-        if (!checkNotifyPermission("notifyDataConnectionRealTimeInfo()")) {
-            return;
-        }
-
-        synchronized (mRecords) {
-            mDcRtInfo = dcRtInfo;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r,
-                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO)) {
-                    try {
-                        if (DBG_LOC) {
-                            log("notifyDataConnectionRealTimeInfo: mDcRtInfo="
-                                    + mDcRtInfo + " r=" + r);
-                        }
-                        r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
     @Override
     public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
@@ -1370,7 +1335,6 @@
                 pw.println("  mCellLocation=" + mCellLocation[i]);
                 pw.println("  mCellInfo=" + mCellInfo.get(i));
             }
-            pw.println("  mDcRtInfo=" + mDcRtInfo);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
                 pw.println("  " + r);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2ee74db..7f783ec 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1242,58 +1242,55 @@
         }
 
         @Override
-        public void setTopicPriority(String pkg, int uid, Notification.Topic topic, int priority) {
+        public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
             checkCallerIsSystem();
-            mRankingHelper.setTopicPriority(pkg, uid, topic, priority);
+            mRankingHelper.setPriority(pkg, uid, topic, priority);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicPriority(String pkg, int uid, Notification.Topic topic) {
+        public int getPriority(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicPriority(pkg, uid, topic);
+            return mRankingHelper.getPriority(pkg, uid, topic);
         }
 
         @Override
-        public void setTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic,
+        public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
                 int visibility) {
             checkCallerIsSystem();
-            mRankingHelper.setTopicVisibilityOverride(pkg, uid, topic, visibility);
+            mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+        public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicVisibilityOverride(pkg, uid, topic);
+            return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
         }
 
         @Override
-        public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
+        public void setImportance(String pkg, int uid, Notification.Topic topic,
                 int importance) {
             enforceSystemOrSystemUI("Caller not system or systemui");
-            if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
-                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
-                        UserHandle.getUserId(uid),
-                        REASON_TOPIC_BANNED, topic, null);
+            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.setTopicImportance(pkg, uid, topic, importance);
+            mRankingHelper.setImportance(pkg, uid, topic, importance);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicImportance(String pkg, int uid, Notification.Topic topic) {
+        public int getImportance(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicImportance(pkg, uid, topic);
-        }
-
-        @Override
-        public void setAppImportance(String pkg, int uid, int importance) {
-            enforceSystemOrSystemUI("Caller not system or systemui");
-            setNotificationsEnabledForPackageImpl(pkg, uid,
-                    importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
-            mRankingHelper.setAppImportance(pkg, uid, importance);
-            savePolicyFile();
+            return mRankingHelper.getImportance(pkg, uid, topic);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 490e890..484b0e9 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -33,6 +33,7 @@
 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;
@@ -106,6 +107,7 @@
         mCreationTimeMs = sbn.getPostTime();
         mUpdateTimeMs = mCreationTimeMs;
         mContext = context;
+        stats = new NotificationUsageStats.SingleNotificationStats();
         mImportance = defaultImportance();
     }
 
@@ -133,27 +135,22 @@
                 importance = IMPORTANCE_MAX;
                 break;
         }
+        stats.requestedImportance = importance;
 
         boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
                 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
                 || n.sound != null
                 || n.vibrate != null;
+        stats.isNoisy = isNoisy;
         if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
             importance = IMPORTANCE_DEFAULT;
         }
-        // maybe only do this for target API < N?
-        if (isNoisy) {
-            if (importance >= IMPORTANCE_HIGH) {
-                importance = IMPORTANCE_MAX;
-            } else {
-                importance = IMPORTANCE_HIGH;
-            }
-        }
 
         if (n.fullScreenIntent != null) {
             importance = IMPORTANCE_MAX;
         }
 
+        stats.naturalImportance = importance;
         return importance;
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 1cdc6db..e75324f 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+
 import android.app.Notification;
 import android.content.ContentValues;
 import android.content.Context;
@@ -101,7 +103,6 @@
      * Called when a notification has been posted.
      */
     public synchronized void registerPostedByApp(NotificationRecord notification) {
-        notification.stats = new SingleNotificationStats();
         notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
 
         AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
@@ -119,13 +120,16 @@
      * Called when a notification has been updated.
      */
     public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
-        notification.stats = old.stats;
+        notification.stats.updateFrom(old.stats);
         AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
         for (AggregatedStats stats : aggregatedStatsArray) {
             stats.numUpdatedByApp++;
             stats.countApiUse(notification);
         }
         releaseAggregatedStatsLocked(aggregatedStatsArray);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logPosted(notification);
+        }
     }
 
     /**
@@ -297,10 +301,6 @@
         public int numWithActions;
         public int numPrivate;
         public int numSecret;
-        public int numPriorityMax;
-        public int numPriorityHigh;
-        public int numPriorityLow;
-        public int numPriorityMin;
         public int numWithBigText;
         public int numWithBigPicture;
         public int numForegroundService;
@@ -314,11 +314,17 @@
         public int numWithSubText;
         public int numWithInfoText;
         public int numInterrupt;
+        public ImportanceHistogram noisyImportance;
+        public ImportanceHistogram quietImportance;
+        public ImportanceHistogram finalImportance;
 
         public AggregatedStats(Context context, String key) {
             this.key = key;
             mContext = context;
             mCreated = SystemClock.elapsedRealtime();
+            noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
+            quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
+            finalImportance = new ImportanceHistogram(context, "note_importance_");
         }
 
         public void countApiUse(NotificationRecord record) {
@@ -354,20 +360,12 @@
                     break;
             }
 
-            switch (n.priority) {
-                case Notification.PRIORITY_MAX:
-                    numPriorityMax++;
-                    break;
-                case Notification.PRIORITY_HIGH:
-                    numPriorityHigh++;
-                    break;
-                case Notification.PRIORITY_LOW:
-                    numPriorityLow++;
-                    break;
-                case Notification.PRIORITY_MIN:
-                    numPriorityMin++;
-                    break;
+            if (record.stats.isNoisy) {
+                noisyImportance.increment(record.stats.requestedImportance);
+            } else {
+                quietImportance.increment(record.stats.requestedImportance);
             }
+            finalImportance.increment(record.getImportance());
 
             final Set<String> names = n.extras.keySet();
             if (names.contains(Notification.EXTRA_BIG_TEXT)) {
@@ -419,10 +417,6 @@
             maybeCount("note_with_actions", (numWithActions - mPrevious.numWithActions));
             maybeCount("note_private", (numPrivate - mPrevious.numPrivate));
             maybeCount("note_secret", (numSecret - mPrevious.numSecret));
-            maybeCount("note_prio_max", (numPriorityMax - mPrevious.numPriorityMax));
-            maybeCount("note_prio_high", (numPriorityHigh - mPrevious.numPriorityHigh));
-            maybeCount("note_prio_low", (numPriorityLow - mPrevious.numPriorityLow));
-            maybeCount("note_prio_min", (numPriorityMin - mPrevious.numPriorityMin));
             maybeCount("note_interupt", (numInterrupt - mPrevious.numInterrupt));
             maybeCount("note_big_text", (numWithBigText - mPrevious.numWithBigText));
             maybeCount("note_big_pic", (numWithBigPicture - mPrevious.numWithBigPicture));
@@ -436,6 +430,9 @@
             maybeCount("note_text", (numWithText - mPrevious.numWithText));
             maybeCount("note_sub_text", (numWithSubText - mPrevious.numWithSubText));
             maybeCount("note_info_text", (numWithInfoText - mPrevious.numWithInfoText));
+            noisyImportance.maybeCount(mPrevious.noisyImportance);
+            quietImportance.maybeCount(mPrevious.quietImportance);
+            finalImportance.maybeCount(mPrevious.finalImportance);
 
             mPrevious.numPostedByApp = numPostedByApp;
             mPrevious.numUpdatedByApp = numUpdatedByApp;
@@ -448,10 +445,6 @@
             mPrevious.numWithActions = numWithActions;
             mPrevious.numPrivate = numPrivate;
             mPrevious.numSecret = numSecret;
-            mPrevious.numPriorityMax = numPriorityMax;
-            mPrevious.numPriorityHigh = numPriorityHigh;
-            mPrevious.numPriorityLow = numPriorityLow;
-            mPrevious.numPriorityMin = numPriorityMin;
             mPrevious.numInterrupt = numInterrupt;
             mPrevious.numWithBigText = numWithBigText;
             mPrevious.numWithBigPicture = numWithBigPicture;
@@ -465,6 +458,9 @@
             mPrevious.numWithText = numWithText;
             mPrevious.numWithSubText = numWithSubText;
             mPrevious.numWithInfoText = numWithInfoText;
+            noisyImportance.update(mPrevious.noisyImportance);
+            quietImportance.update(mPrevious.quietImportance);
+            finalImportance.update(mPrevious.finalImportance);
         }
 
         void maybeCount(String name, int value) {
@@ -483,17 +479,64 @@
         }
 
         private String toStringWithIndent(String indent) {
-            return indent + "AggregatedStats{\n" +
-                    indent + "  key='" + key + "',\n" +
-                    indent + "  numPostedByApp=" + numPostedByApp + ",\n" +
-                    indent + "  numUpdatedByApp=" + numUpdatedByApp + ",\n" +
-                    indent + "  numRemovedByApp=" + numRemovedByApp + ",\n" +
-                    indent + "  numPeopleCacheHit=" + numPeopleCacheHit + ",\n" +
-                    indent + "  numWithStaredPeople=" + numWithStaredPeople + ",\n" +
-                    indent + "  numWithValidPeople=" + numWithValidPeople + ",\n" +
-                    indent + "  numPeopleCacheMiss=" + numPeopleCacheMiss + ",\n" +
-                    indent + "  numBlocked=" + numBlocked + ",\n" +
-                    indent + "}";
+            StringBuilder output = new StringBuilder();
+            output.append(indent).append("AggregatedStats{\n");
+            String indentPlusTwo = indent + "  ";
+            output.append(indentPlusTwo);
+            output.append("key='").append(key).append("',\n");
+            output.append(indentPlusTwo);
+            output.append("numPostedByApp=").append(numPostedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numUpdatedByApp=").append(numUpdatedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numRemovedByApp=").append(numRemovedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPeopleCacheHit=").append(numPeopleCacheHit).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithStaredPeople=").append(numWithStaredPeople).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithValidPeople=").append(numWithValidPeople).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPeopleCacheMiss=").append(numPeopleCacheMiss).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numBlocked=").append(numBlocked).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithActions=").append(numWithActions).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPrivate=").append(numPrivate).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numSecret=").append(numSecret).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numInterrupt=").append(numInterrupt).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithBigText=").append(numWithBigText).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithBigPicture=").append(numWithBigPicture).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numForegroundService=").append(numForegroundService).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numOngoing=").append(numOngoing).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numAutoCancel=").append(numAutoCancel).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithLargeIcon=").append(numWithLargeIcon).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithInbox=").append(numWithInbox).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithMediaSession=").append(numWithMediaSession).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithTitle=").append(numWithTitle).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithText=").append(numWithText).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithSubText=").append(numWithSubText).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithInfoText=").append(numWithInfoText).append("\n");
+            output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
+            output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
+            output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
+            output.append(indent).append("}");
+            return output.toString();
         }
 
         public JSONObject dumpJson() throws JSONException {
@@ -511,10 +554,6 @@
             maybePut(dump, "numWithActions", numWithActions);
             maybePut(dump, "numPrivate", numPrivate);
             maybePut(dump, "numSecret", numSecret);
-            maybePut(dump, "numPriorityMax", numPriorityMax);
-            maybePut(dump, "numPriorityHigh", numPriorityHigh);
-            maybePut(dump, "numPriorityLow", numPriorityLow);
-            maybePut(dump, "numPriorityMin", numPriorityMin);
             maybePut(dump, "numInterrupt", numInterrupt);
             maybePut(dump, "numWithBigText", numWithBigText);
             maybePut(dump, "numWithBigPicture", numWithBigPicture);
@@ -528,6 +567,10 @@
             maybePut(dump, "numWithText", numWithText);
             maybePut(dump, "numWithSubText", numWithSubText);
             maybePut(dump, "numWithInfoText", numWithInfoText);
+            noisyImportance.maybePut(dump, mPrevious.noisyImportance);
+            quietImportance.maybePut(dump, mPrevious.quietImportance);
+            finalImportance.maybePut(dump, mPrevious.finalImportance);
+
             return dump;
         }
 
@@ -538,6 +581,65 @@
         }
     }
 
+    private static class ImportanceHistogram {
+        // TODO define these somewhere else
+        private static final int NUM_IMPORTANCES = 5;
+        private static final String[] IMPORTANCE_NAMES = {"none", "low", "default", "high", "max"};
+        private final Context mContext;
+        private final String[] mCounterNames;
+        private final String mPrefix;
+        private int[] mCount;
+
+        ImportanceHistogram(Context context, String prefix) {
+            mContext = context;
+            mCount = new int[NUM_IMPORTANCES];
+            mCounterNames = new String[NUM_IMPORTANCES];
+            mPrefix = prefix;
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                mCounterNames[i] = mPrefix + IMPORTANCE_NAMES[i];
+            }
+        }
+
+        void increment(int imp) {
+            imp = imp < 0 ? 0 : imp > NUM_IMPORTANCES ? NUM_IMPORTANCES : imp;
+            mCount[imp] ++;
+        }
+
+        void maybeCount(ImportanceHistogram prev) {
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                final int value = mCount[i] - prev.mCount[i];
+                if (value > 0) {
+                    MetricsLogger.count(mContext, mCounterNames[i], value);
+                }
+            }
+        }
+
+        void update(ImportanceHistogram that) {
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                mCount[i] = that.mCount[i];
+            }
+        }
+
+        public void maybePut(JSONObject dump, ImportanceHistogram prev)
+                throws JSONException {
+            dump.put(mPrefix, new JSONArray(mCount));
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder output = new StringBuilder();
+            output.append(mPrefix).append(": [");
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                output.append(mCount[i]);
+                if (i < (NUM_IMPORTANCES-1)) {
+                    output.append(", ");
+                }
+            }
+            output.append("]");
+            return output.toString();
+        }
+    }
+
     /**
      * Tracks usage of an individual notification that is currently active.
      */
@@ -575,6 +677,12 @@
         public long airtimeExpandedMs = 0;
         /** Number of times the notification has been expanded by the user. */
         public long userExpansionCount = 0;
+        /** Importance directly requested by the app. */
+        public int requestedImportance;
+        /** Did the app include sound or vibration on the notificaiton. */
+        public boolean isNoisy;
+        /** Importance after initial filtering for noise and other features */
+        public int naturalImportance;
 
         public long getCurrentPosttimeMs() {
             if (posttimeElapsedMs < 0) {
@@ -686,17 +794,40 @@
 
         @Override
         public String toString() {
-            return "SingleNotificationStats{" +
-                    "posttimeElapsedMs=" + posttimeElapsedMs +
-                    ", posttimeToFirstClickMs=" + posttimeToFirstClickMs +
-                    ", posttimeToDismissMs=" + posttimeToDismissMs +
-                    ", airtimeCount=" + airtimeCount +
-                    ", airtimeMs=" + airtimeMs +
-                    ", currentAirtimeStartElapsedMs=" + currentAirtimeStartElapsedMs +
-                    ", airtimeExpandedMs=" + airtimeExpandedMs +
-                    ", posttimeToFirstVisibleExpansionMs=" + posttimeToFirstVisibleExpansionMs +
-                    ", currentAirtimeExpandedSEMs=" + currentAirtimeExpandedStartElapsedMs +
-                    '}';
+            StringBuilder output = new StringBuilder();
+            output.append("SingleNotificationStats{");
+
+            output.append("posttimeElapsedMs=").append(posttimeElapsedMs).append(", ");
+            output.append("posttimeToFirstClickMs=").append(posttimeToFirstClickMs).append(", ");
+            output.append("posttimeToDismissMs=").append(posttimeToDismissMs).append(", ");
+            output.append("airtimeCount=").append(airtimeCount).append(", ");
+            output.append("airtimeMs=").append(airtimeMs).append(", ");
+            output.append("currentAirtimeStartElapsedMs=").append(currentAirtimeStartElapsedMs)
+                    .append(", ");
+            output.append("airtimeExpandedMs=").append(airtimeExpandedMs).append(", ");
+            output.append("posttimeToFirstVisibleExpansionMs=")
+                    .append(posttimeToFirstVisibleExpansionMs).append(", ");
+            output.append("currentAirtimeExpandedStartElapsedMs=")
+                    .append(currentAirtimeExpandedStartElapsedMs).append(", ");
+            output.append("requestedImportance=").append(requestedImportance).append(", ");
+            output.append("naturalImportance=").append(naturalImportance).append(", ");
+            output.append("isNoisy=").append(isNoisy);
+            output.append('}');
+            return output.toString();
+        }
+
+        /** Copy useful information out of the stats from the pre-update notifications. */
+        public void updateFrom(SingleNotificationStats old) {
+            posttimeElapsedMs = old.posttimeElapsedMs;
+            posttimeToFirstClickMs = old.posttimeToFirstClickMs;
+            airtimeCount = old.airtimeCount;
+            posttimeToFirstAirtimeMs = old.posttimeToFirstAirtimeMs;
+            currentAirtimeStartElapsedMs = old.currentAirtimeStartElapsedMs;
+            airtimeMs = old.airtimeMs;
+            posttimeToFirstVisibleExpansionMs = old.posttimeToFirstVisibleExpansionMs;
+            currentAirtimeExpandedStartElapsedMs = old.currentAirtimeExpandedStartElapsedMs;
+            airtimeExpandedMs = old.airtimeExpandedMs;
+            userExpansionCount = old.userExpansionCount;
         }
     }
 
@@ -741,7 +872,7 @@
         private static final int MSG_DISMISS = 4;
 
         private static final String DB_NAME = "notification_log.db";
-        private static final int DB_VERSION = 4;
+        private static final int DB_VERSION = 5;
 
         /** Age in ms after which events are pruned from the DB. */
         private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L;  // 1 week
@@ -762,7 +893,11 @@
         private static final String COL_WHEN_MS = "when_ms";
         private static final String COL_DEFAULTS = "defaults";
         private static final String COL_FLAGS = "flags";
-        private static final String COL_PRIORITY = "priority";
+        private static final String COL_IMPORTANCE_REQ = "importance_request";
+        private static final String COL_IMPORTANCE_FINAL = "importance_final";
+        private static final String COL_NOISY = "noisy";
+        private static final String COL_MUTED = "muted";
+        private static final String COL_DEMOTED = "demoted";
         private static final String COL_CATEGORY = "category";
         private static final String COL_ACTION_COUNT = "action_count";
         private static final String COL_POSTTIME_MS = "posttime_ms";
@@ -776,14 +911,28 @@
         private static final int EVENT_TYPE_CLICK = 2;
         private static final int EVENT_TYPE_REMOVE = 3;
         private static final int EVENT_TYPE_DISMISS = 4;
-
         private static long sLastPruneMs;
+
         private static long sNumWrites;
-
         private final SQLiteOpenHelper mHelper;
-        private final Handler mWriteHandler;
 
+        private final Handler mWriteHandler;
         private static final long DAY_MS = 24 * 60 * 60 * 1000;
+        private static final String STATS_QUERY = "SELECT " +
+                COL_EVENT_USER_ID + ", " +
+                COL_PKG + ", " +
+                // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
+                "CAST(((%d - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+                "AS day, " +
+                "COUNT(*) AS cnt, " +
+                "SUM(" + COL_MUTED + ") as muted, " +
+                "SUM(" + COL_NOISY + ") as noisy, " +
+                "SUM(" + COL_DEMOTED + ") as demoted " +
+                "FROM " + TAB_LOG + " " +
+                "WHERE " +
+                COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
+                " AND " + COL_EVENT_TIME + " > %d " +
+                " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
 
         public SQLiteLog(Context context) {
             HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
@@ -828,7 +977,11 @@
                             COL_WHEN_MS + " INT," +
                             COL_DEFAULTS + " INT," +
                             COL_FLAGS + " INT," +
-                            COL_PRIORITY + " INT," +
+                            COL_IMPORTANCE_REQ + " INT," +
+                            COL_IMPORTANCE_FINAL + " INT," +
+                            COL_NOISY + " INT," +
+                            COL_MUTED + " INT," +
+                            COL_DEMOTED + " INT," +
                             COL_CATEGORY + " TEXT," +
                             COL_ACTION_COUNT + " INT," +
                             COL_POSTTIME_MS + " INT," +
@@ -841,8 +994,7 @@
 
                 @Override
                 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-                    if (oldVersion <= 3) {
-                        // Version 3 creation left 'log' in a weird state. Just reset for now.
+                    if (oldVersion != newVersion) {
                         db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
                         onCreate(db);
                     }
@@ -866,22 +1018,11 @@
             mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
         }
 
-        private JSONArray JsonPostFrequencies(DumpFilter filter) throws JSONException {
+        private JSONArray jsonPostFrequencies(DumpFilter filter) throws JSONException {
             JSONArray frequencies = new JSONArray();
             SQLiteDatabase db = mHelper.getReadableDatabase();
             long midnight = getMidnightMs();
-            String q = "SELECT " +
-                    COL_EVENT_USER_ID + ", " +
-                    COL_PKG + ", " +
-                    // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
-                    "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
-                    "AS day, " +
-                    "COUNT(*) AS cnt " +
-                    "FROM " + TAB_LOG + " " +
-                    "WHERE " +
-                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
-                    " AND " + COL_EVENT_TIME + " > " + filter.since +
-                    " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            String q = String.format(STATS_QUERY, midnight, filter.since);
             Cursor cursor = db.rawQuery(q, null);
             try {
                 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -890,11 +1031,17 @@
                     if (filter != null && !filter.matches(pkg)) continue;
                     int day = cursor.getInt(2);
                     int count = cursor.getInt(3);
+                    int muted = cursor.getInt(4);
+                    int noisy = cursor.getInt(5);
+                    int demoted = cursor.getInt(6);
                     JSONObject row = new JSONObject();
                     row.put("user_id", userId);
                     row.put("package", pkg);
                     row.put("day", day);
                     row.put("count", count);
+                    row.put("noisy", noisy);
+                    row.put("muted", muted);
+                    row.put("demoted", demoted);
                     frequencies.put(row);
                 }
             } finally {
@@ -906,17 +1053,7 @@
         public void printPostFrequencies(PrintWriter pw, String indent, DumpFilter filter) {
             SQLiteDatabase db = mHelper.getReadableDatabase();
             long midnight = getMidnightMs();
-            String q = "SELECT " +
-                    COL_EVENT_USER_ID + ", " +
-                    COL_PKG + ", " +
-                    // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
-                    "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
-                        "AS day, " +
-                    "COUNT(*) AS cnt " +
-                    "FROM " + TAB_LOG + " " +
-                    "WHERE " +
-                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
-                    "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            String q = String.format(STATS_QUERY, midnight, filter.since);
             Cursor cursor = db.rawQuery(q, null);
             try {
                 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -925,8 +1062,12 @@
                     if (filter != null && !filter.matches(pkg)) continue;
                     int day = cursor.getInt(2);
                     int count = cursor.getInt(3);
+                    int muted = cursor.getInt(4);
+                    int noisy = cursor.getInt(5);
+                    int demoted = cursor.getInt(6);
                     pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
-                            ",day=" + day + ",count=" + count + "}");
+                            ",day=" + day + ",count=" + count + ",muted=" + muted + "/" + noisy +
+                            ",demoted=" + demoted + "}");
                 }
             } finally {
                 cursor.close();
@@ -985,7 +1126,18 @@
             }
             outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
             outCv.put(COL_FLAGS, r.getNotification().flags);
-            outCv.put(COL_PRIORITY, r.getNotification().priority);
+            final int before = r.stats.requestedImportance;
+            final int after = r.getImportance();
+            final boolean noisy = r.stats.isNoisy;
+            outCv.put(COL_IMPORTANCE_REQ, before);
+            outCv.put(COL_IMPORTANCE_FINAL, after);
+            outCv.put(COL_DEMOTED, after < before ? 1 : 0);
+            outCv.put(COL_NOISY, noisy);
+            if (noisy && after < IMPORTANCE_HIGH) {
+                outCv.put(COL_MUTED, 1);
+            } else {
+                outCv.put(COL_MUTED, 0);
+            }
             if (r.getNotification().category != null) {
                 outCv.put(COL_CATEGORY, r.getNotification().category);
             }
@@ -1008,7 +1160,9 @@
         public JSONObject dumpJson(DumpFilter filter) {
             JSONObject dump = new JSONObject();
             try {
-                dump.put("post_frequency", JsonPostFrequencies(filter));
+                dump.put("post_frequency", jsonPostFrequencies(filter));
+                dump.put("since", filter.since);
+                dump.put("now", System.currentTimeMillis());
             } catch (JSONException e) {
                 // pass
             }
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 9b10ef2..7f85e1f 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -23,20 +23,18 @@
 
     List<Notification.Topic> getTopics(String packageName, int uid);
 
-    int getTopicPriority(String packageName, int uid, Notification.Topic topic);
+    int getPriority(String packageName, int uid, Notification.Topic topic);
 
-    void setTopicPriority(String packageName, int uid, Notification.Topic topic, int priority);
+    void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
 
-    int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+    int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
 
-    void setTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic,
+    void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
             int visibility);
 
-    void setTopicImportance(String packageName, int uid, Notification.Topic topic, int importance);
+    void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
 
-    int getTopicImportance(String packageName, int uid, Notification.Topic topic);
-
-    void setAppImportance(String packageName, int uid, int importance);
+    int getImportance(String packageName, int uid, Notification.Topic topic);
 
     boolean doesAppUseTopics(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 ce4ecd3..827482f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -164,6 +164,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.
@@ -245,7 +247,15 @@
             }
             out.startTag(null, TAG_PACKAGE);
             out.attribute(null, ATT_NAME, r.pkg);
-            out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+            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));
@@ -373,66 +383,109 @@
     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()) {
+        for (Topic t : r.topics.values()) {
             topics.add(t.topic);
         }
         return topics;
     }
 
+    /**
+     * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
+     * priority of the app.
+     */
     @Override
-    public int getTopicPriority(String packageName, int uid, Notification.Topic topic) {
+    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 setTopicPriority(String packageName, int uid, Notification.Topic topic,
+    public void setPriority(String packageName, int uid, Notification.Topic topic,
             int priority) {
         final Record r = getOrCreateRecord(packageName, uid);
-        getOrCreateTopic(r, topic).priority = priority;
-        updateConfig();
-    }
-
-    @Override
-    public int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        return getOrCreateTopic(r, topic).visibility;
-    }
-
-    @Override
-    public void setTopicVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
-        int visibility) {
-        final Record r = getOrCreateRecord(pkgName, uid);
-        getOrCreateTopic(r, topic).visibility = visibility;
-        updateConfig();
-    }
-
-    @Override
-    public int getTopicImportance(String packageName, int uid, Notification.Topic topic) {
-        final Record r = getOrCreateRecord(packageName, uid);
-        return getOrCreateTopic(r, topic).importance;
-    }
-
-    @Override
-    public void setTopicImportance(String pkgName, int uid, Notification.Topic topic,
-            int importance) {
-        final Record r = getOrCreateRecord(pkgName, uid);
-        getOrCreateTopic(r, topic).importance = importance;
+        if (topic == null) {
+            r.priority = priority;
+            for (Topic t : r.topics.values()) {
+                t.priority = priority;
+            }
+        } else {
+            getOrCreateTopic(r, topic).priority = priority;
+        }
         updateConfig();
     }
 
     /**
-     * Sets the default importance for all new topics that appear in the future, and resets
+     * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
+     * override of the app.
+     */
+    @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;
+    }
+
+    /**
+     * 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.
+     */
+    @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;
+        }
+        updateConfig();
+    }
+
+    /**
+     * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
+     * importance of the app.
+     */
+    @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 setAppImportance(String pkgName, int uid, int importance) {
+    public void setImportance(String pkgName, int uid, Notification.Topic topic,
+            int importance) {
         final Record r = getOrCreateRecord(pkgName, uid);
-        r.importance = importance;
-        if (Ranking.IMPORTANCE_NONE != importance) {
-            for (Topic t : r.topics.values()) {
-                t.importance = importance;
+        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;
         }
         updateConfig();
     }
@@ -459,6 +512,8 @@
         } 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;
         }
@@ -503,8 +558,18 @@
                 pw.print(" (");
                 pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
                 pw.print(')');
-                pw.print(" importance=");
-                pw.print(Ranking.importanceToString(r.importance));
+                if (r.importance != DEFAULT_IMPORTANCE) {
+                    pw.print(" importance=");
+                    pw.print(Ranking.importanceToString(r.importance));
+                }
+                if (r.priority != DEFAULT_PRIORITY) {
+                    pw.print(" priority=");
+                    pw.print(Ranking.importanceToString(r.priority));
+                }
+                if (r.visibility != DEFAULT_VISIBILITY) {
+                    pw.print(" visibility=");
+                    pw.print(Ranking.importanceToString(r.visibility));
+                }
                 pw.println();
                 for (Topic t : r.topics.values()) {
                     pw.print(prefix);
@@ -561,6 +626,8 @@
         String pkg;
         int uid = UNKNOWN_UID;
         int importance = DEFAULT_IMPORTANCE;
+        int priority = DEFAULT_PRIORITY;
+        int visibility = DEFAULT_VISIBILITY;
         Map<String, Topic> topics = new ArrayMap<>();
    }
 
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
index 01770d0..c6b3e0f 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int topicImportance = mConfig.getTopicImportance(record.sbn.getPackageName(),
+        final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
                 record.sbn.getUid(), record.sbn.getNotification().getTopic());
         record.setTopicImportance(topicImportance);
 
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
index 5bf989ae..1df5c2b 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int packagePriority = mConfig.getTopicPriority(record.sbn.getPackageName(),
+        final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
                 record.sbn.getUid(), record.sbn.getNotification().getTopic());
         record.setPackagePriority(packagePriority);
 
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
index e053382..eaa3ed3 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int packageVisibility = mConfig.getTopicVisibilityOverride(
+        final int packageVisibility = mConfig.getVisibilityOverride(
                 record.sbn.getPackageName(), record.sbn.getUid(),
                 record.sbn.getNotification().getTopic());
         record.setPackageVisibilityOverride(packageVisibility);
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 2640889..31182fc 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -155,16 +155,12 @@
 
     @SmallTest
     public void testTopicImportanceExtractor() throws Exception {
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("A", "a"),
-                IMPORTANCE_MAX);
+        mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
         // There is no B. There never was a b. Moving on...
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("C", "c"),
-                IMPORTANCE_HIGH);
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("D", "d"),
-                IMPORTANCE_LOW);
+        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.setTopicImportance("package2", 0, new Notification.Topic("E", "e"),
-                IMPORTANCE_NONE);
+        mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
 
         TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
         validator.process(mRecordGroupGSortA);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 16472c8..ae130d4 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -194,10 +194,12 @@
      * {@more}
      * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
      * READ_PRECISE_PHONE_STATE}
-     *
      * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+     *
+     * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
      * @hide
      */
+    @Deprecated
     public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 76b69ce..907d76e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -21,7 +21,6 @@
 import android.net.NetworkCapabilities;
 import android.os.Bundle;
 import android.telephony.CellInfo;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
@@ -65,7 +64,6 @@
     void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
             String failCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
-    void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
     void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
     void notifySubscriptionInfoChanged();