Merge "Remove refs to BatteryStats in ProcessRecord"
diff --git a/Android.bp b/Android.bp
index 459f179..3957f7e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -479,6 +479,8 @@
         "media/java/android/media/tv/ITvRemoteServiceInput.aidl",
         "media/java/android/service/media/IMediaBrowserService.aidl",
         "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
+        "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl",
+        "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl",
         "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl",
         "telecomm/java/com/android/internal/telecom/IVideoCallback.aidl",
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
index e126fb8..2b8b8f2 100644
--- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
@@ -23,6 +23,8 @@
 
 import com.android.internal.os.BinderCallsStats;
 
+import java.util.Random;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -45,7 +47,7 @@
 
     @Before
     public void setUp() {
-        mBinderCallsStats = new BinderCallsStats();
+        mBinderCallsStats = new BinderCallsStats(new Random());
     }
 
     @After
diff --git a/api/current.txt b/api/current.txt
index e3db256..9a47a66 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40959,6 +40959,16 @@
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
+  public abstract class CallRedirectionService extends android.app.Service {
+    ctor public CallRedirectionService();
+    method public final void cancelCall();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+    method public final void placeCallUnmodified();
+    method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
+  }
+
   public abstract class CallScreeningService extends android.app.Service {
     ctor public CallScreeningService();
     method public android.os.IBinder onBind(android.content.Intent);
@@ -70711,7 +70721,7 @@
     ctor public InflaterInputStream(java.io.InputStream);
     method protected void fill() throws java.io.IOException;
     field protected byte[] buf;
-    field protected boolean closed;
+    field protected deprecated boolean closed;
     field protected java.util.zip.Inflater inf;
     field protected int len;
   }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1119eb3..0c241fc 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -403,7 +403,7 @@
     fprintf(out, "\n              *Note: If both UID and NAME are omitted then all configs will\n");
     fprintf(out, "\n                     be removed from memory and disk!\n");
     fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME [--proto]\n");
+    fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME [--include_current_bucket] [--proto]\n");
     fprintf(out, "  Dump all metric data for a configuration.\n");
     fprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
     fprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
@@ -567,12 +567,17 @@
         int argCount = args.size();
         bool good = false;
         bool proto = false;
+        bool includeCurrentBucket = false;
         int uid;
         string name;
         if (!std::strcmp("--proto", args[argCount-1].c_str())) {
             proto = true;
             argCount -= 1;
         }
+        if (!std::strcmp("--include_current_bucket", args[argCount-1].c_str())) {
+            includeCurrentBucket = true;
+            argCount -= 1;
+        }
         if (argCount == 2) {
             // Automatically pick the UID
             uid = IPCThreadState::self()->getCallingUid();
@@ -600,7 +605,7 @@
         if (good) {
             vector<uint8_t> data;
             mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
-                                     false /* include_current_bucket*/, ADB_DUMP, &data);
+                                     includeCurrentBucket, ADB_DUMP, &data);
             if (proto) {
                 for (size_t i = 0; i < data.size(); i ++) {
                     fprintf(out, "%c", data[i]);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 279ed02..bf033a7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -49,7 +49,7 @@
     oneof pushed {
         // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
         BleScanStateChanged ble_scan_state_changed = 2;
-        // 3 is available for use
+        ProcessStateChanged process_state_changed = 3;
         BleScanResultReceived ble_scan_result_received = 4;
         SensorStateChanged sensor_state_changed = 5;
         GpsScanStateChanged gps_scan_state_changed = 6;
@@ -60,7 +60,12 @@
         LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 11;
         MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12;
         WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13;
-        // 14 - 19 are available
+        ActivityManagerSleepStateChanged activity_manager_sleep_state_changed = 14;
+        MemoryFactorStateChanged memory_factor_state_changed = 15;
+        ExcessiveCpuUsageReported excessive_cpu_usage_reported = 16;
+        CachedKillReported cached_kill_reported = 17;
+        ProcessMemoryStatReported process_memory_stat_reported = 18;
+        // 19 is available
         BatterySaverModeStateChanged battery_saver_mode_state_changed = 20;
         DeviceIdleModeStateChanged device_idle_mode_state_changed = 21;
         DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22;
@@ -126,7 +131,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10023
+    // Next: 10024
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -151,6 +156,7 @@
         FullBatteryCapacity full_battery_capacity = 10020;
         Temperature temperature = 10021;
         BinderCalls binder_calls = 10022;
+        BinderCallsExceptions binder_calls_exceptions = 10023;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -210,7 +216,8 @@
 }
 
 /**
- * Logs that the state of a process state, as per the activity manager, has changed.
+ * Logs that the process state of the uid, as determined by ActivityManager
+ * (i.e. the highest process state of that uid's processes) has changed.
  *
  * Logged from:
  *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -223,6 +230,112 @@
 }
 
 /**
+ * Logs process state change of a process, as per the activity manager.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
+ */
+message ProcessStateChanged {
+    optional int32 uid = 1;
+    optional string process_name = 2;
+    optional string package_name = 3;
+    // TODO: remove this when validation is done
+    optional int64 version = 5;
+    // The state, from frameworks/base/core/proto/android/app/enums.proto.
+    optional android.app.ProcessStateEnum state = 4;
+}
+
+/**
+ * Logs when ActivityManagerService sleep state is changed.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+ */
+message ActivityManagerSleepStateChanged {
+    // TODO: import frameworks proto
+    enum State {
+        UNKNOWN = 0;
+        ASLEEP = 1;
+        AWAKE = 2;
+    }
+    optional State state = 1 [(stateFieldOption).option = EXCLUSIVE];
+}
+
+/**
+ * Logs when system memory state changes.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message MemoryFactorStateChanged {
+    // TODO: import frameworks proto
+    enum State {
+        MEMORY_UNKNOWN = 0;
+        NORMAL = 1;     // normal.
+        MODERATE = 2;   // moderate memory pressure.
+        LOW = 3;        // low memory.
+        CRITICAL = 4;   // critical memory.
+
+    }
+    optional State factor = 1 [(stateFieldOption).option = EXCLUSIVE];
+}
+
+/**
+ * Logs when app is using too much cpu, according to ActivityManagerService.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message ExcessiveCpuUsageReported {
+    optional int32 uid = 1;
+    optional string process_name = 2;
+    optional string package_name = 3;
+    // package version. TODO: remove this when validation is done
+    optional int64 version = 4;
+}
+
+/**
+ * Logs when a cached process is killed, along with its pss.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message CachedKillReported {
+    optional int32 uid = 1;
+    optional string process_name = 2;
+    optional string package_name = 3;
+    // TODO: remove this when validation is done
+    optional int64 version = 5;
+    optional int64 pss = 4;
+}
+
+/**
+ * Logs when memory stats of a process is reported.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
+ */
+message ProcessMemoryStatReported {
+    optional int32 uid = 1;
+    optional string process_name = 2;
+    optional string package_name = 3;
+    //TODO: remove this when validation is done
+    optional int64 version = 9;
+    optional int64 pss = 4;
+    optional int64 uss = 5;
+    optional int64 rss = 6;
+    enum Type {
+        ADD_PSS_INTERNAL_SINGLE = 0;
+        ADD_PSS_INTERNAL_ALL_MEM = 1;
+        ADD_PSS_INTERNAL_ALL_POLL = 2;
+        ADD_PSS_EXTERNAL = 3;
+        ADD_PSS_EXTERNAL_SLOW = 4;
+    }
+    optional Type type = 7;
+    optional int64 duration = 8;
+}
+
+/**
  * Logs that a process started, finished, crashed, or ANRed.
  *
  * Logged from:
@@ -1982,35 +2095,67 @@
  *
  * Binder stats are cumulative from boot unless somebody reset the data using
  * > adb shell dumpsys binder_calls_stats --reset
+ *
+ * Next tag: 14
  */
 message BinderCalls {
-   // TODO(gaillard): figure out if binder call stats includes data from isolated uids, if a uid
-   // gets recycled and we have isolated uids, we might attribute the data incorrectly.
-   // TODO(gaillard): there is a high dimensions cardinality, figure out if we should drop the less
-   // commonly used APIs.
-   optional int32 uid = 1 [(is_uid) = true];
-   // Fully qualified class name of the API call.
-   optional string service_class_name = 2;
-   // Method name of the API call. It can also be a transaction code if we cannot resolve it to a
-   // name. See Binder#getTransactionName.
-   optional string service_method_name = 3;
-   // Total number of API calls.
-   optional int64 call_count = 4;
-   // Number of exceptions thrown by the API.
-   optional int64 exception_count = 5;
-   // Total latency of all API calls.
-   // Average can be computed using total_latency_micros / call_count.
-   optional int64 total_latency_micros = 6;
-   // Maximum latency of one API call.
-   optional int64 max_latency_micros = 7;
-   // Total CPU usage of all API calls.
-   optional int64 total_cpu_micros = 8;
-   // Maximum CPU usage of one API call.
-   optional int64 max_cpu_micros = 9;
-   // Maximum parcel reply size of one API call.
-   optional int64 max_reply_size_bytes = 10;
-   // Maximum parcel request size of one API call.
-   optional int64 max_request_size_bytes = 11;
+    optional int32 uid = 1 [(is_uid) = true];
+    // Fully qualified class name of the API call.
+    //
+    // This is a system server class name.
+    //
+    // TODO(gaillard): figure out if binder call stats includes data from isolated uids, if a uid
+    // gets recycled and we have isolated uids, we might attribute the data incorrectly.
+    // TODO(gaillard): there is a high dimensions cardinality, figure out if we should drop the less
+    // commonly used APIs.
+    optional string service_class_name = 2;
+    // Method name of the API call. It can also be a transaction code if we cannot
+    // resolve it to a name. See Binder#getTransactionName.
+    //
+    // This is a system server method name.
+    optional string service_method_name = 3;
+    // Total number of API calls.
+    optional int64 call_count = 4;
+    // True if the screen was interactive PowerManager#isInteractive at the end of the call.
+    optional bool screen_interactive = 13;
+    // Total number of API calls we have data recorded for. If we collected data for all the calls,
+    // call_count will be equal to recorded_call_count.
+    //
+    // If recorded_call_count is different than call_count, it means data collection has been
+    // sampled. All the fields below will be sampled in this case.
+    optional int64 recorded_call_count = 12;
+    // Number of exceptions thrown by the API.
+    optional int64 recorded_exception_count = 5;
+    // Total latency of all API calls.
+    // Average can be computed using total_latency_micros / recorded_call_count.
+    optional int64 recorded_total_latency_micros = 6;
+    // Maximum latency of one API call.
+    optional int64 recorded_max_latency_micros = 7;
+    // Total CPU usage of all API calls.
+    // Average can be computed using total_cpu_micros / recorded_call_count.
+    // Total can be computed using total_cpu_micros / recorded_call_count * call_count.
+    optional int64 recorded_total_cpu_micros = 8;
+    // Maximum CPU usage of one API call.
+    optional int64 recorded_max_cpu_micros = 9;
+    // Maximum parcel reply size of one API call.
+    optional int64 recorded_max_reply_size_bytes = 10;
+    // Maximum parcel request size of one API call.
+    optional int64 recorded_max_request_size_bytes = 11;
+}
+
+/**
+ * Pulls the statistics of exceptions during calls to Binder.
+ *
+ * Binder stats are cumulative from boot unless somebody reset the data using
+ * > adb shell dumpsys binder_calls_stats --reset
+ */
+message BinderCallsExceptions {
+    // Exception class name, e.g. java.lang.IllegalArgumentException.
+    //
+    // This is an exception class name thrown by the system server.
+    optional string exception_class_name = 1;
+    // Total number of exceptions.
+    optional int64 exception_count = 2;
 }
 
 /**
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index d81e2dc..3e9077b 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -3210,6 +3210,7 @@
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_SEARCHABLE:Ljava/lang/String;
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_SEASON_DISPLAY_NUMBER:Ljava/lang/String;
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_SEASON_TITLE:Ljava/lang/String;
+Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_SERIES_ID:Ljava/lang/String;
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_SHORT_DESCRIPTION:Ljava/lang/String;
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_THUMBNAIL_URI:Ljava/lang/String;
 Landroid/media/tv/TvContract$ProgramColumns;->COLUMN_TITLE:Ljava/lang/String;
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
new file mode 100644
index 0000000..05de3e8
--- /dev/null
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a class member, that is not part of the SDK, is used by apps.
+ * Since the member is not part of the SDK, such use is not supported.
+ *
+ * This annotation acts as a heads up that changing a given method or field
+ * may affect apps, potentially breaking them when the next Android version is
+ * released. In some cases, for members that are heavily used, this annotation
+ * may imply restrictions on changes to the member.
+ *
+ * This annotation also results in access to the member being permitted by the
+ * runtime, with a warning being generated in debug builds.
+ *
+ * For more details, see go/UnsupportedAppUsage.
+ *
+ * {@hide}
+ */
+@Retention(CLASS)
+@Target({CONSTRUCTOR, METHOD, FIELD})
+public @interface UnsupportedAppUsage {
+
+    /**
+     * Associates a bug tracking the work to add a public alternative to this API. Optional.
+     *
+     * @return ID of the associated tracking bug
+     */
+    long trackingBug() default 0;
+
+    /**
+     * For debug use only. The expected dex signature to be generated for this API, used to verify
+     * parts of the build process.
+     *
+     * @return A dex API signature.
+     */
+    String expectedSignature() default "";
+}
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 69852f3..6f73d02 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -33,7 +33,7 @@
     // Perms.
     void grantSlicePermission(String callingPkg, String toPkg, in Uri uri);
     void revokeSlicePermission(String callingPkg, String toPkg, in Uri uri);
-    int checkSlicePermission(in Uri uri, String pkg, int pid, int uid,
+    int checkSlicePermission(in Uri uri, String callingPkg, String pkg, int pid, int uid,
             in String[] autoGrantPermissions);
     void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
 }
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 26498e8..955093d 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -430,7 +430,8 @@
      */
     public @PermissionResult int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
         try {
-            return mService.checkSlicePermission(uri, null, pid, uid, null);
+            return mService.checkSlicePermission(uri, mContext.getPackageName(), null, pid, uid,
+                    null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -487,7 +488,8 @@
             if (pkg == null) {
                 throw new SecurityException("No pkg specified");
             }
-            int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions);
+            int result = mService.checkSlicePermission(uri, mContext.getPackageName(), pkg, pid,
+                    uid, autoGrantPermissions);
             if (result == PERMISSION_DENIED) {
                 throw new SecurityException("User " + uid + " does not have slice permission for "
                         + uri + ".");
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 0fb84b7..b7f5cdf 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -24,8 +24,6 @@
 import android.os.StrictMode;
 import android.util.Log;
 
-import libcore.net.UriCodec;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -1959,7 +1957,8 @@
         if (s == null) {
             return null;
         }
-        return UriCodec.decode(s, false, StandardCharsets.UTF_8, false);
+        return UriCodec.decode(
+                s, false /* convertPlus */, StandardCharsets.UTF_8, false /* throwOnFailure */);
     }
 
     /**
diff --git a/core/java/android/net/UriCodec.java b/core/java/android/net/UriCodec.java
new file mode 100644
index 0000000..e1470e0
--- /dev/null
+++ b/core/java/android/net/UriCodec.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Decodes “application/x-www-form-urlencoded” content.
+ *
+ * @hide
+ */
+public final class UriCodec {
+
+    private UriCodec() {}
+
+    /**
+     * Interprets a char as hex digits, returning a number from -1 (invalid char) to 15 ('f').
+     */
+    private static int hexCharToValue(char c) {
+        if ('0' <= c && c <= '9') {
+            return c - '0';
+        }
+        if ('a' <= c && c <= 'f') {
+            return 10 + c - 'a';
+        }
+        if ('A' <= c && c <= 'F') {
+            return 10 + c - 'A';
+        }
+        return -1;
+    }
+
+    private static URISyntaxException unexpectedCharacterException(
+            String uri, String name, char unexpected, int index) {
+        String nameString = (name == null) ? "" :  " in [" + name + "]";
+        return new URISyntaxException(
+                uri, "Unexpected character" + nameString + ": " + unexpected, index);
+    }
+
+    private static char getNextCharacter(String uri, int index, int end, String name)
+             throws URISyntaxException {
+        if (index >= end) {
+            String nameString = (name == null) ? "" :  " in [" + name + "]";
+            throw new URISyntaxException(
+                    uri, "Unexpected end of string" + nameString, index);
+        }
+        return uri.charAt(index);
+    }
+
+    /**
+     * Decode a string according to the rules of this decoder.
+     *
+     * - if {@code convertPlus == true} all ‘+’ chars in the decoded output are converted to ‘ ‘
+     *   (white space)
+     * - if {@code throwOnFailure == true}, an {@link IllegalArgumentException} is thrown for
+     *   invalid inputs. Else, U+FFFd is emitted to the output in place of invalid input octets.
+     */
+    public static String decode(
+            String s, boolean convertPlus, Charset charset, boolean throwOnFailure) {
+        StringBuilder builder = new StringBuilder(s.length());
+        appendDecoded(builder, s, convertPlus, charset, throwOnFailure);
+        return builder.toString();
+    }
+
+    /**
+     * Character to be output when there's an error decoding an input.
+     */
+    private static final char INVALID_INPUT_CHARACTER = '\ufffd';
+
+    private static void appendDecoded(
+            StringBuilder builder,
+            String s,
+            boolean convertPlus,
+            Charset charset,
+            boolean throwOnFailure) {
+        CharsetDecoder decoder = charset.newDecoder()
+                .onMalformedInput(CodingErrorAction.REPLACE)
+                .replaceWith("\ufffd")
+                .onUnmappableCharacter(CodingErrorAction.REPORT);
+        // Holds the bytes corresponding to the escaped chars being read (empty if the last char
+        // wasn't a escaped char).
+        ByteBuffer byteBuffer = ByteBuffer.allocate(s.length());
+        int i = 0;
+        while (i < s.length()) {
+            char c = s.charAt(i);
+            i++;
+            switch (c) {
+                case '+':
+                    flushDecodingByteAccumulator(
+                            builder, decoder, byteBuffer, throwOnFailure);
+                    builder.append(convertPlus ? ' ' : '+');
+                    break;
+                case '%':
+                    // Expect two characters representing a number in hex.
+                    byte hexValue = 0;
+                    for (int j = 0; j < 2; j++) {
+                        try {
+                            c = getNextCharacter(s, i, s.length(), null /* name */);
+                        } catch (URISyntaxException e) {
+                            // Unexpected end of input.
+                            if (throwOnFailure) {
+                                throw new IllegalArgumentException(e);
+                            } else {
+                                flushDecodingByteAccumulator(
+                                        builder, decoder, byteBuffer, throwOnFailure);
+                                builder.append(INVALID_INPUT_CHARACTER);
+                                return;
+                            }
+                        }
+                        i++;
+                        int newDigit = hexCharToValue(c);
+                        if (newDigit < 0) {
+                            if (throwOnFailure) {
+                                throw new IllegalArgumentException(
+                                        unexpectedCharacterException(s, null /* name */, c, i - 1));
+                            } else {
+                                flushDecodingByteAccumulator(
+                                        builder, decoder, byteBuffer, throwOnFailure);
+                                builder.append(INVALID_INPUT_CHARACTER);
+                                break;
+                            }
+                        }
+                        hexValue = (byte) (hexValue * 0x10 + newDigit);
+                    }
+                    byteBuffer.put(hexValue);
+                    break;
+                default:
+                    flushDecodingByteAccumulator(builder, decoder, byteBuffer, throwOnFailure);
+                    builder.append(c);
+            }
+        }
+        flushDecodingByteAccumulator(builder, decoder, byteBuffer, throwOnFailure);
+    }
+
+    private static void flushDecodingByteAccumulator(
+            StringBuilder builder,
+            CharsetDecoder decoder,
+            ByteBuffer byteBuffer,
+            boolean throwOnFailure) {
+        if (byteBuffer.position() == 0) {
+            return;
+        }
+        byteBuffer.flip();
+        try {
+            builder.append(decoder.decode(byteBuffer));
+        } catch (CharacterCodingException e) {
+            if (throwOnFailure) {
+                throw new IllegalArgumentException(e);
+            } else {
+                builder.append(INVALID_INPUT_CHARACTER);
+            }
+        } finally {
+            // Use the byte buffer to write again.
+            byteBuffer.flip();
+            byteBuffer.limit(byteBuffer.capacity());
+        }
+    }
+}
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index b6c6bdc..5a7a83f 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -151,14 +151,14 @@
     @Override
     public String toString() {
         return new StringBuilder(Condition.class.getSimpleName()).append('[')
-            .append("id=").append(id)
-            .append(",summary=").append(summary)
-            .append(",line1=").append(line1)
-            .append(",line2=").append(line2)
-            .append(",icon=").append(icon)
-            .append(",state=").append(stateToString(state))
-            .append(",flags=").append(flags)
-            .append(']').toString();
+                .append("state=").append(stateToString(state))
+                .append(",id=").append(id)
+                .append(",summary=").append(summary)
+                .append(",line1=").append(line1)
+                .append(",line2=").append(line2)
+                .append(",icon=").append(icon)
+                .append(",flags=").append(flags)
+                .append(']').toString();
     }
 
     /** @hide */
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index f52234d..5ac36afc 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -240,11 +240,29 @@
                 .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
                 .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
                 .append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
-                .append(",automaticRules=").append(automaticRules)
-                .append(",manualRule=").append(manualRule)
+                .append(",\nautomaticRules=").append(rulesToString())
+                .append(",\nmanualRule=").append(manualRule)
                 .append(']').toString();
     }
 
+    private String rulesToString() {
+        if (automaticRules.isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(automaticRules.size() * 28);
+        buffer.append('{');
+        for (int i = 0; i < automaticRules.size(); i++) {
+            if (i > 0) {
+                buffer.append(",\n");
+            }
+            Object value = automaticRules.valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+
     private Diff diff(ZenModeConfig to) {
         final Diff d = new Diff();
         if (to == null) {
@@ -1027,10 +1045,10 @@
 
     public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
         final boolean isSchedule =  conditionId != null
-                && conditionId.getScheme().equals(Condition.SCHEME)
-                && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+                && Condition.SCHEME.equals(conditionId.getScheme())
+                && ZenModeConfig.SYSTEM_AUTHORITY.equals(conditionId.getAuthority())
                 && conditionId.getPathSegments().size() == 1
-                && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
+                && ZenModeConfig.SCHEDULE_PATH.equals(conditionId.getPathSegments().get(0));
         if (!isSchedule) return null;
         final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
         final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
@@ -1128,10 +1146,10 @@
 
     public static EventInfo tryParseEventConditionId(Uri conditionId) {
         final boolean isEvent = conditionId != null
-                && conditionId.getScheme().equals(Condition.SCHEME)
-                && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+                && Condition.SCHEME.equals(conditionId.getScheme())
+                && ZenModeConfig.SYSTEM_AUTHORITY.equals(conditionId.getAuthority())
                 && conditionId.getPathSegments().size() == 1
-                && conditionId.getPathSegments().get(0).equals(EVENT_PATH);
+                && EVENT_PATH.equals(conditionId.getPathSegments().get(0));
         if (!isEvent) return null;
         final EventInfo rt = new EventInfo();
         rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL);
@@ -1340,14 +1358,14 @@
         @Override
         public String toString() {
             return new StringBuilder(ZenRule.class.getSimpleName()).append('[')
-                    .append("enabled=").append(enabled)
+                    .append("id=").append(id)
+                    .append(",enabled=").append(String.valueOf(enabled).toUpperCase())
                     .append(",snoozing=").append(snoozing)
                     .append(",name=").append(name)
                     .append(",zenMode=").append(Global.zenModeToString(zenMode))
                     .append(",conditionId=").append(conditionId)
                     .append(",condition=").append(condition)
                     .append(",component=").append(component)
-                    .append(",id=").append(id)
                     .append(",creationTime=").append(creationTime)
                     .append(",enabler=").append(enabler)
                     .append(']').toString();
@@ -1479,7 +1497,7 @@
             final int N = lines.size();
             for (int i = 0; i < N; i++) {
                 if (i > 0) {
-                    sb.append(',');
+                    sb.append(",\n");
                 }
                 sb.append(lines.get(i));
             }
diff --git a/core/java/android/util/Base64OutputStream.java b/core/java/android/util/Base64OutputStream.java
index 4535d1c..8378705 100644
--- a/core/java/android/util/Base64OutputStream.java
+++ b/core/java/android/util/Base64OutputStream.java
@@ -117,8 +117,10 @@
                 out.flush();
             }
         } catch (IOException e) {
-            if (thrown != null) {
+            if (thrown == null) {
                 thrown = e;
+            } else {
+                thrown.addSuppressed(e);
             }
         }
 
diff --git a/core/java/android/util/jar/StrictJarFile.java b/core/java/android/util/jar/StrictJarFile.java
index bc4a19d..11aee2f 100644
--- a/core/java/android/util/jar/StrictJarFile.java
+++ b/core/java/android/util/jar/StrictJarFile.java
@@ -390,6 +390,7 @@
     public static class ZipInflaterInputStream extends InflaterInputStream {
         private final ZipEntry entry;
         private long bytesRead = 0;
+        private boolean closed;
 
         public ZipInflaterInputStream(InputStream is, Inflater inf, int bsize, ZipEntry entry) {
             super(is, inf, bsize);
@@ -424,6 +425,12 @@
             }
             return super.available() == 0 ? 0 : (int) (entry.getSize() - bytesRead);
         }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+            closed = true;
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index f87c081..63c7dd0 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -38,6 +38,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
+import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.ToDoubleFunction;
@@ -57,7 +58,7 @@
     private static final int MAX_EXCEPTION_COUNT_SIZE = 50;
     private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow";
     private static final CallSession NOT_ENABLED = new CallSession();
-    private static final BinderCallsStats sInstance = new BinderCallsStats();
+    private static final BinderCallsStats sInstance = new BinderCallsStats(new Random());
 
     private volatile boolean mEnabled = ENABLED_DEFAULT;
     private volatile boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT;
@@ -68,12 +69,12 @@
     private final ArrayMap<String, Integer> mExceptionCounts = new ArrayMap<>();
     private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>();
     private final Object mLock = new Object();
+    private final Random mRandom;
     private long mStartTime = System.currentTimeMillis();
-    @GuardedBy("mLock")
-    private UidEntry mSampledEntries = new UidEntry(-1);
 
     @VisibleForTesting  // Use getInstance() instead.
-    public BinderCallsStats() {
+    public BinderCallsStats(Random random) {
+        this.mRandom = random;
     }
 
     public CallSession callStarted(Binder binder, int code) {
@@ -82,7 +83,7 @@
 
     private CallSession callStarted(String className, int code, @Nullable String methodName) {
         if (!mEnabled) {
-          return NOT_ENABLED;
+            return NOT_ENABLED;
         }
 
         CallSession s = mCallSessionsPool.poll();
@@ -98,16 +99,12 @@
         s.timeStarted = -1;
 
         synchronized (mLock) {
-            if (mDetailedTracking) {
-                s.cpuTimeStarted = getThreadTimeMicro();
-                s.timeStarted = getElapsedRealtimeMicro();
-            } else {
-                s.sampledCallStat = mSampledEntries.getOrCreate(s.callStat);
-                if (s.sampledCallStat.callCount % mPeriodicSamplingInterval == 0) {
-                    s.cpuTimeStarted = getThreadTimeMicro();
-                    s.timeStarted = getElapsedRealtimeMicro();
-                }
+            if (!mDetailedTracking && !shouldTrackCall()) {
+                return s;
             }
+
+            s.cpuTimeStarted = getThreadTimeMicro();
+            s.timeStarted = getElapsedRealtimeMicro();
         }
         return s;
     }
@@ -115,7 +112,7 @@
     public void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
         Preconditions.checkNotNull(s);
         if (s == NOT_ENABLED) {
-          return;
+            return;
         }
 
         processCallEnded(s, parcelRequestSize, parcelReplySize);
@@ -128,60 +125,42 @@
     private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
         synchronized (mLock) {
             if (!mEnabled) {
-              return;
+                return;
             }
 
-            long duration;
-            long latencyDuration;
-            if (mDetailedTracking) {
-                duration = getThreadTimeMicro() - s.cpuTimeStarted;
-                latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
-            } else {
-                CallStat cs = s.sampledCallStat;
-                // Non-negative time signals beginning of the new sampling interval
-                if (s.cpuTimeStarted >= 0) {
-                    duration = getThreadTimeMicro() - s.cpuTimeStarted;
-                    latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
-                } else {
-                    // callCount is always incremented, but time only once per sampling interval
-                    long samplesCount = cs.callCount / mPeriodicSamplingInterval + 1;
-                    duration = cs.cpuTimeMicros / samplesCount;
-                    latencyDuration = cs.latencyMicros / samplesCount;
-                }
-            }
-
-            int callingUid = getCallingUid();
-
+            final int callingUid = getCallingUid();
             UidEntry uidEntry = mUidEntries.get(callingUid);
             if (uidEntry == null) {
                 uidEntry = new UidEntry(callingUid);
                 mUidEntries.put(callingUid, uidEntry);
             }
-
-            CallStat callStat;
-            if (mDetailedTracking) {
-                // Find CallStat entry and update its total time
-                callStat = uidEntry.getOrCreate(s.callStat);
-                callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
-                callStat.maxRequestSizeBytes =
-                        Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
-                callStat.maxReplySizeBytes =
-                        Math.max(callStat.maxReplySizeBytes, parcelReplySize);
-            } else {
-                // update sampled timings in the beginning of each interval
-                callStat = s.sampledCallStat;
-            }
+            uidEntry.callCount++;
+            CallStat callStat = uidEntry.getOrCreate(s.callStat);
             callStat.callCount++;
-            callStat.methodName = s.callStat.methodName;
-            if (s.cpuTimeStarted >= 0) {
+
+            // Non-negative time signals we need to record data for this call.
+            final boolean recordCall = s.cpuTimeStarted >= 0;
+            if (recordCall) {
+                final long duration = getThreadTimeMicro() - s.cpuTimeStarted;
+                final long latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
+                uidEntry.cpuTimeMicros += duration;
+                uidEntry.recordedCallCount++;
+
+                callStat.recordedCallCount++;
+                callStat.methodName = s.callStat.methodName;
                 callStat.cpuTimeMicros += duration;
                 callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration);
                 callStat.latencyMicros += latencyDuration;
-                callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
+                callStat.maxLatencyMicros =
+                        Math.max(callStat.maxLatencyMicros, latencyDuration);
+                if (mDetailedTracking) {
+                    callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
+                    callStat.maxRequestSizeBytes =
+                            Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
+                    callStat.maxReplySizeBytes =
+                            Math.max(callStat.maxReplySizeBytes, parcelReplySize);
+                }
             }
-
-            uidEntry.cpuTimeMicros += duration;
-            uidEntry.callCount++;
         }
     }
 
@@ -195,28 +174,28 @@
     public void callThrewException(CallSession s, Exception exception) {
         Preconditions.checkNotNull(s);
         if (!mEnabled) {
-          return;
+            return;
         }
         s.exceptionThrown = true;
         try {
             String className = exception.getClass().getName();
             synchronized (mLock) {
                 if (mExceptionCounts.size() >= MAX_EXCEPTION_COUNT_SIZE) {
-                  className = EXCEPTION_COUNT_OVERFLOW_NAME;
+                    className = EXCEPTION_COUNT_OVERFLOW_NAME;
                 }
                 Integer count = mExceptionCounts.get(className);
                 mExceptionCounts.put(className, count == null ? 1 : count + 1);
             }
         } catch (RuntimeException e) {
-          // Do not propagate the exception. We do not want to swallow original exception.
-          Log.wtf(TAG, "Unexpected exception while updating mExceptionCounts", e);
+            // Do not propagate the exception. We do not want to swallow original exception.
+            Log.wtf(TAG, "Unexpected exception while updating mExceptionCounts", e);
         }
     }
 
     public ArrayList<ExportedCallStat> getExportedCallStats() {
         // We do not collect all the data if detailed tracking is off.
         if (!mDetailedTracking) {
-          return new ArrayList<ExportedCallStat>();
+            return new ArrayList<ExportedCallStat>();
         }
 
         ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>();
@@ -229,11 +208,12 @@
                     exported.uid = entry.uid;
                     exported.className = stat.className;
                     exported.methodName = stat.methodName == null
-                        ? String.valueOf(stat.msg) : stat.methodName;
+                            ? String.valueOf(stat.msg) : stat.methodName;
                     exported.cpuTimeMicros = stat.cpuTimeMicros;
                     exported.maxCpuTimeMicros = stat.maxCpuTimeMicros;
                     exported.latencyMicros = stat.latencyMicros;
                     exported.maxLatencyMicros = stat.maxLatencyMicros;
+                    exported.recordedCallCount = stat.recordedCallCount;
                     exported.callCount = stat.callCount;
                     exported.maxRequestSizeBytes = stat.maxRequestSizeBytes;
                     exported.maxReplySizeBytes = stat.maxReplySizeBytes;
@@ -254,14 +234,16 @@
 
     private void dumpLocked(PrintWriter pw, Map<Integer,String> appIdToPkgNameMap, boolean verbose) {
         if (!mEnabled) {
-          pw.println("Binder calls stats disabled.");
-          return;
+            pw.println("Binder calls stats disabled.");
+            return;
         }
 
         long totalCallsCount = 0;
+        long totalRecordedCallsCount = 0;
         long totalCpuTime = 0;
         pw.print("Start time: ");
         pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartTime));
+        pw.println("Sampling interval period: " + mPeriodicSamplingInterval);
         List<UidEntry> entries = new ArrayList<>();
 
         int uidEntriesSize = mUidEntries.size();
@@ -269,70 +251,53 @@
             UidEntry e = mUidEntries.valueAt(i);
             entries.add(e);
             totalCpuTime += e.cpuTimeMicros;
+            totalRecordedCallsCount += e.recordedCallCount;
             totalCallsCount += e.callCount;
         }
 
         entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed());
         String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) ";
         StringBuilder sb = new StringBuilder();
-        if (mDetailedTracking) {
-            pw.println("Per-UID raw data " + datasetSizeDesc
-                    + "(package/uid, call_desc, cpu_time_micros, max_cpu_time_micros, "
-                    + "latency_time_micros, max_latency_time_micros, exception_count, "
-                    + "max_request_size_bytes, max_reply_size_bytes, call_count):");
-            List<UidEntry> topEntries = verbose ? entries
-                    : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
-            for (UidEntry uidEntry : topEntries) {
-                for (CallStat e : uidEntry.getCallStatsList()) {
-                    sb.setLength(0);
-                    sb.append("    ")
-                            .append(uidToString(uidEntry.uid, appIdToPkgNameMap))
-                            .append(",").append(e)
-                            .append(',').append(e.cpuTimeMicros)
-                            .append(',').append(e.maxCpuTimeMicros)
-                            .append(',').append(e.latencyMicros)
-                            .append(',').append(e.maxLatencyMicros)
-                            .append(',').append(e.exceptionCount)
-                            .append(',').append(e.maxRequestSizeBytes)
-                            .append(',').append(e.maxReplySizeBytes)
-                            .append(',').append(e.callCount);
-                    pw.println(sb);
-                }
-            }
-            pw.println();
-        } else {
-            pw.println("Sampled stats " + datasetSizeDesc
-                    + "(call_desc, cpu_time, call_count, exception_count):");
-            List<CallStat> sampledStatsList = mSampledEntries.getCallStatsList();
-            // Show all if verbose, otherwise 90th percentile
-            if (!verbose) {
-                sampledStatsList = getHighestValues(sampledStatsList,
-                        value -> value.cpuTimeMicros, 0.9);
-            }
-            for (CallStat e : sampledStatsList) {
+        List<UidEntry> topEntries = verbose ? entries
+                : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
+        pw.println("Per-UID raw data " + datasetSizeDesc
+                + "(package/uid, call_desc, cpu_time_micros, max_cpu_time_micros, "
+                + "latency_time_micros, max_latency_time_micros, exception_count, "
+                + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, "
+                + "call_count):");
+        for (UidEntry uidEntry : topEntries) {
+            for (CallStat e : uidEntry.getCallStatsList()) {
                 sb.setLength(0);
-                sb.append("    ").append(e)
-                        .append(',').append(e.cpuTimeMicros * mPeriodicSamplingInterval)
-                        .append(',').append(e.callCount)
-                        .append(',').append(e.exceptionCount);
+                sb.append("    ")
+                        .append(uidToString(uidEntry.uid, appIdToPkgNameMap))
+                        .append(',').append(e)
+                        .append(',').append(e.cpuTimeMicros)
+                        .append(',').append(e.maxCpuTimeMicros)
+                        .append(',').append(e.latencyMicros)
+                        .append(',').append(e.maxLatencyMicros)
+                        .append(',').append(mDetailedTracking ? e.exceptionCount : '_')
+                        .append(',').append(mDetailedTracking ? e.maxRequestSizeBytes : '_')
+                        .append(',').append(mDetailedTracking ? e.maxReplySizeBytes : '_')
+                        .append(',').append(e.recordedCallCount)
+                        .append(',').append(e.callCount);
                 pw.println(sb);
             }
-            pw.println();
         }
+        pw.println();
         pw.println("Per-UID Summary " + datasetSizeDesc
-                + "(cpu_time, % of total cpu_time, call_count, exception_count, package/uid):");
+                + "(cpu_time, % of total cpu_time, recorded_call_count, call_count, package/uid):");
         List<UidEntry> summaryEntries = verbose ? entries
                 : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
         for (UidEntry entry : summaryEntries) {
             String uidStr = uidToString(entry.uid, appIdToPkgNameMap);
-            pw.println(String.format("  %10d %3.0f%% %8d %3d %s",
-                    entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime, entry.callCount,
-                    entry.exceptionCount, uidStr));
+            pw.println(String.format("  %10d %3.0f%% %8d %8d %s",
+                        entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime,
+                        entry.recordedCallCount, entry.callCount, uidStr));
         }
         pw.println();
         pw.println(String.format("  Summary: total_cpu_time=%d, "
-                        + "calls_count=%d, avg_call_cpu_time=%.0f",
-                totalCpuTime, totalCallsCount, (double)totalCpuTime / totalCallsCount));
+                    + "calls_count=%d, avg_call_cpu_time=%.0f",
+                    totalCpuTime, totalCallsCount, (double)totalCpuTime / totalRecordedCallsCount));
         pw.println();
 
         pw.println("Exceptions thrown (exception_count, class_name):");
@@ -340,10 +305,15 @@
         // We cannot use new ArrayList(Collection) constructor because MapCollections does not
         // implement toArray method.
         mExceptionCounts.entrySet().iterator().forEachRemaining(
-            (e) -> exceptionEntries.add(Pair.create(e.getKey(), e.getValue())));
+                (e) -> exceptionEntries.add(Pair.create(e.getKey(), e.getValue())));
         exceptionEntries.sort((e1, e2) -> Integer.compare(e2.second, e1.second));
         for (Pair<String, Integer> entry : exceptionEntries) {
-          pw.println(String.format("  %6d %s", entry.second, entry.first));
+            pw.println(String.format("  %6d %s", entry.second, entry.first));
+        }
+
+        if (!mDetailedTracking && mPeriodicSamplingInterval != 1) {
+            pw.println("");
+            pw.println("/!\\ Displayed data is sampled. See sampling interval at the top.");
         }
     }
 
@@ -366,16 +336,20 @@
         return SystemClock.elapsedRealtimeNanos() / 1000;
     }
 
+    private boolean shouldTrackCall() {
+        return mRandom.nextInt() % mPeriodicSamplingInterval == 0;
+    }
+
     public static BinderCallsStats getInstance() {
         return sInstance;
     }
 
     public void setDetailedTracking(boolean enabled) {
         synchronized (mLock) {
-          if (enabled != mDetailedTracking) {
-              mDetailedTracking = enabled;
-              reset();
-          }
+            if (enabled != mDetailedTracking) {
+                mDetailedTracking = enabled;
+                reset();
+            }
         }
     }
 
@@ -401,7 +375,6 @@
         synchronized (mLock) {
             mUidEntries.clear();
             mExceptionCounts.clear();
-            mSampledEntries.mCallStats.clear();
             mStartTime = System.currentTimeMillis();
         }
     }
@@ -418,6 +391,7 @@
         public long latencyMicros;
         public long maxLatencyMicros;
         public long callCount;
+        public long recordedCallCount;
         public long maxRequestSizeBytes;
         public long maxReplySizeBytes;
         public long exceptionCount;
@@ -430,11 +404,21 @@
         // Method name might be null when we cannot resolve the transaction code. For instance, if
         // the binder was not generated by AIDL.
         public @Nullable String methodName;
+        // Number of calls for which we collected data for. We do not record data for all the calls
+        // when sampling is on.
+        public long recordedCallCount;
+        // Real number of total calls.
+        public long callCount;
+        // Total CPU of all for all the recorded calls.
+        // Approximate total CPU usage can be computed by
+        // cpuTimeMicros * callCount / recordedCallCount
         public long cpuTimeMicros;
         public long maxCpuTimeMicros;
+        // Total latency of all for all the recorded calls.
+        // Approximate average latency can be computed by
+        // latencyMicros * callCount / recordedCallCount
         public long latencyMicros;
         public long maxLatencyMicros;
-        public long callCount;
         // The following fields are only computed if mDetailedTracking is set.
         public long maxRequestSizeBytes;
         public long maxReplySizeBytes;
@@ -455,7 +439,6 @@
             }
 
             CallStat callStat = (CallStat) o;
-
             return msg == callStat.msg && (className.equals(callStat.className));
         }
 
@@ -477,15 +460,20 @@
         long timeStarted;
         boolean exceptionThrown;
         final CallStat callStat = new CallStat();
-        CallStat sampledCallStat;
     }
 
     @VisibleForTesting
     public static class UidEntry {
         int uid;
-        public long cpuTimeMicros;
+        // Number of calls for which we collected data for. We do not record data for all the calls
+        // when sampling is on.
+        public long recordedCallCount;
+        // Real number of total calls.
         public long callCount;
-        public int exceptionCount;
+        // Total CPU of all for all the recorded calls.
+        // Approximate total CPU usage can be computed by
+        // cpuTimeMicros * callCount / recordedCallCount
+        public long cpuTimeMicros;
 
         UidEntry(int uid) {
             this.uid = uid;
@@ -551,11 +539,6 @@
     }
 
     @VisibleForTesting
-    public UidEntry getSampledEntries() {
-        return mSampledEntries;
-    }
-
-    @VisibleForTesting
     public ArrayMap<String, Integer> getExceptionCounts() {
         return mExceptionCounts;
     }
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index a9cd5c8..e37e650 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -30,14 +30,13 @@
 import android.util.Slog;
 import com.android.internal.logging.AndroidConfig;
 import com.android.server.NetworkManagementSocketTagger;
+import dalvik.system.RuntimeHooks;
 import dalvik.system.VMRuntime;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Objects;
-import java.util.TimeZone;
 import java.util.logging.LogManager;
-import org.apache.harmony.luni.internal.util.TimezoneGetter;
 
 /**
  * Main entry point for runtime initialization.  Not for
@@ -195,19 +194,13 @@
          * the default handler, but not the pre handler.
          */
         LoggingHandler loggingHandler = new LoggingHandler();
-        Thread.setUncaughtExceptionPreHandler(loggingHandler);
+        RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
         Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
 
         /*
-         * Install a TimezoneGetter subclass for ZoneInfo.db
+         * Install a time zone supplier that uses the Android persistent time zone system property.
          */
-        TimezoneGetter.setInstance(new TimezoneGetter() {
-            @Override
-            public String getId() {
-                return SystemProperties.get("persist.sys.timezone");
-            }
-        });
-        TimeZone.setDefault(null);
+        RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
 
         /*
          * Sets handler for java.util.logging to use Android log facilities.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index da19560..8f87f91 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -21,9 +21,6 @@
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.icu.impl.CacheValue;
-import android.icu.text.DecimalFormatSymbols;
-import android.icu.util.ULocale;
 import android.opengl.EGL14;
 import android.os.Build;
 import android.os.Environment;
@@ -122,9 +119,9 @@
 
     static void preload(TimingsTraceLog bootTimingsTraceLog) {
         Log.d(TAG, "begin preload");
-        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
-        beginIcuCachePinning();
-        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
+        bootTimingsTraceLog.traceBegin("BeginPreload");
+        beginPreload();
+        bootTimingsTraceLog.traceEnd(); // BeginPreload
         bootTimingsTraceLog.traceBegin("PreloadClasses");
         preloadClasses();
         bootTimingsTraceLog.traceEnd(); // PreloadClasses
@@ -142,7 +139,7 @@
         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
         // for memory sharing purposes.
         WebViewFactory.prepareWebViewInZygote();
-        endIcuCachePinning();
+        endPreload();
         warmUpJcaProviders();
         Log.d(TAG, "end preload");
 
@@ -156,27 +153,16 @@
         preload(new TimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
     }
 
-    private static void beginIcuCachePinning() {
-        // Pin ICU data in memory from this point that would normally be held by soft references.
-        // Without this, any references created immediately below or during class preloading
-        // would be collected when the Zygote GC runs in gcAndFinalize().
-        Log.i(TAG, "Installing ICU cache reference pinning...");
+    private static void beginPreload() {
+        Log.i(TAG, "Calling ZygoteHooks.beginPreload()");
 
-        CacheValue.setStrength(CacheValue.Strength.STRONG);
-
-        Log.i(TAG, "Preloading ICU data...");
-        // Explicitly exercise code to cache data apps are likely to need.
-        ULocale[] localesToPin = { ULocale.ROOT, ULocale.US, ULocale.getDefault() };
-        for (ULocale uLocale : localesToPin) {
-            new DecimalFormatSymbols(uLocale);
-        }
+        ZygoteHooks.onBeginPreload();
     }
 
-    private static void endIcuCachePinning() {
-        // All cache references created by ICU from this point will be soft.
-        CacheValue.setStrength(CacheValue.Strength.SOFT);
+    private static void endPreload() {
+        ZygoteHooks.onEndPreload();
 
-        Log.i(TAG, "Uninstalled ICU cache reference pinning...");
+        Log.i(TAG, "Called ZygoteHooks.endPreload()");
     }
 
     private static void preloadSharedLibraries() {
@@ -436,15 +422,8 @@
      * softly- and final-reachable objects, along with any other garbage.
      * This is only useful just before a fork().
      */
-    /*package*/ static void gcAndFinalize() {
-        final VMRuntime runtime = VMRuntime.getRuntime();
-
-        /* runFinalizationSync() lets finalizers be called in Zygote,
-         * which doesn't have a HeapWorker thread.
-         */
-        System.gc();
-        runtime.runFinalizationSync();
-        System.gc();
+    private static void gcAndFinalize() {
+        ZygoteHooks.gcAndFinalize();
     }
 
     /**
diff --git a/core/tests/coretests/src/android/net/UriCodecTest.java b/core/tests/coretests/src/android/net/UriCodecTest.java
new file mode 100644
index 0000000..7fe9402
--- /dev/null
+++ b/core/tests/coretests/src/android/net/UriCodecTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tests for {@link UriCodec}
+ */
+public class UriCodecTest extends TestCase {
+
+    public void testDecode_emptyString_returnsEmptyString() {
+        assertEquals("", UriCodec.decode("",
+                false /* convertPlus */,
+                StandardCharsets.UTF_8,
+                true /* throwOnFailure */));
+    }
+
+    public void testDecode_wrongHexDigit_fails() {
+        try {
+            // %p in the end.
+            UriCodec.decode("ab%2f$%C4%82%25%e0%a1%80%p",
+                    false /* convertPlus */,
+                    StandardCharsets.UTF_8,
+                    true /* throwOnFailure */);
+            fail("Expected URISyntaxException");
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testDecode_secondHexDigitWrong_fails() {
+        try {
+            // %1p in the end.
+            UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%1p",
+                    false /* convertPlus */,
+                    StandardCharsets.UTF_8,
+                    true /* throwOnFailure */);
+            fail("Expected URISyntaxException");
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testDecode_endsWithPercent_fails() {
+        try {
+            // % in the end.
+            UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%",
+                    false /* convertPlus */,
+                    StandardCharsets.UTF_8,
+                    true /* throwOnFailure */);
+            fail("Expected URISyntaxException");
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testDecode_dontThrowException_appendsUnknownCharacter() {
+        assertEquals("ab/$\u0102%\u0840\ufffd",
+                UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%",
+                        false /* convertPlus */,
+                        StandardCharsets.UTF_8,
+                        false /* throwOnFailure */));
+    }
+
+    public void testDecode_convertPlus() {
+        assertEquals("ab/$\u0102% \u0840",
+                UriCodec.decode("ab%2f$%c4%82%25+%e0%a1%80",
+                        true /* convertPlus */,
+                        StandardCharsets.UTF_8,
+                        false /* throwOnFailure */));
+    }
+
+    // Last character needs decoding (make sure we are flushing the buffer with chars to decode).
+    public void testDecode_lastCharacter() {
+        assertEquals("ab/$\u0102%\u0840",
+                UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80",
+                        false /* convertPlus */,
+                        StandardCharsets.UTF_8,
+                        true /* throwOnFailure */));
+    }
+
+    // Check that a second row of encoded characters is decoded properly (internal buffers are
+    // reset properly).
+    public void testDecode_secondRowOfEncoded() {
+        assertEquals("ab/$\u0102%\u0840aa\u0840",
+                UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80aa%e0%a1%80",
+                        false /* convertPlus */,
+                        StandardCharsets.UTF_8,
+                        true /* throwOnFailure */));
+    }
+}
diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java
index 3aee583..af608c3 100644
--- a/core/tests/coretests/src/android/util/Base64Test.java
+++ b/core/tests/coretests/src/android/util/Base64Test.java
@@ -18,13 +18,18 @@
 
 import android.support.test.filters.LargeTest;
 
+import junit.framework.TestCase;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Random;
-import junit.framework.TestCase;
+import java.util.stream.Collectors;
 
 @LargeTest
 public class Base64Test extends TestCase {
@@ -530,4 +535,74 @@
             assertEquals(plain, actual);
         }
     }
+
+    public void testOutputStream_ioExceptionDuringClose() {
+        OutputStream out = new OutputStream() {
+            @Override public void write(int b) throws IOException { }
+            @Override public void close() throws IOException {
+                throw new IOException("close()");
+            }
+        };
+        OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
+        try {
+            out2.close();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testOutputStream_ioExceptionDuringCloseAndWrite() {
+        OutputStream out = new OutputStream() {
+            @Override public void write(int b) throws IOException {
+                throw new IOException("write()");
+            }
+            @Override public void write(byte[] b) throws IOException {
+                throw new IOException("write()");
+            }
+            @Override public void write(byte[] b, int off, int len) throws IOException {
+                throw new IOException("write()");
+            }
+            @Override public void close() throws IOException {
+                throw new IOException("close()");
+            }
+        };
+        OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
+        try {
+            out2.close();
+            fail();
+        } catch (IOException expected) {
+            // Base64OutputStream write()s pending (possibly empty) data
+            // before close(), so the IOE from write() should be thrown and
+            // any later exception suppressed.
+            assertEquals("write()", expected.getMessage());
+            Throwable[] suppressed = expected.getSuppressed();
+            List<String> suppressedMessages = Arrays.asList(suppressed).stream()
+                    .map((e) -> e.getMessage())
+                    .collect(Collectors.toList());
+            assertEquals(Collections.singletonList("close()"), suppressedMessages);
+        }
+    }
+
+    public void testOutputStream_ioExceptionDuringWrite() {
+        OutputStream out = new OutputStream() {
+            @Override public void write(int b) throws IOException {
+                throw new IOException("write()");
+            }
+            @Override public void write(byte[] b) throws IOException {
+                throw new IOException("write()");
+            }
+            @Override public void write(byte[] b, int off, int len) throws IOException {
+                throw new IOException("write()");
+            }
+        };
+        // Base64OutputStream write()s pending (possibly empty) data
+        // before close(), so the IOE from write() should be thrown.
+        OutputStream out2 = new Base64OutputStream(out, Base64.DEFAULT);
+        try {
+            out2.close();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index d46c154..07e2af8 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -33,6 +33,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 
 import static org.junit.Assert.assertEquals;
 
@@ -48,6 +49,7 @@
     public void testDetailedOff() {
         TestBinderCallsStats bcs = new TestBinderCallsStats();
         bcs.setDetailedTracking(false);
+        bcs.setSamplingInterval(5);
 
         Binder binder = new Binder();
         BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
@@ -58,44 +60,31 @@
         assertEquals(1, uidEntries.size());
         BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
         Assert.assertNotNull(uidEntry);
+        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
         assertEquals(1, uidEntry.callCount);
+        assertEquals(1, uidEntry.recordedCallCount);
         assertEquals(10, uidEntry.cpuTimeMicros);
-        assertEquals("Detailed tracking off - no entries should be returned",
-                0, uidEntry.getCallStatsList().size());
+        assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
+        assertEquals(1, callStatsList.get(0).msg);
 
-        BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
-        List<BinderCallsStats.CallStat> sampledCallStatsList = sampledEntries.getCallStatsList();
-        assertEquals(1, sampledCallStatsList.size());
-
-
-        assertEquals(1, sampledCallStatsList.get(0).callCount);
-        assertEquals(10, sampledCallStatsList.get(0).cpuTimeMicros);
-        assertEquals(binder.getClass().getName(), sampledCallStatsList.get(0).className);
-        assertEquals(1, sampledCallStatsList.get(0).msg);
-
+        // CPU usage is sampled, should not be tracked here.
         callSession = bcs.callStarted(binder, 1);
         bcs.time += 20;
         bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
-
-        uidEntry = bcs.getUidEntries().get(TEST_UID);
         assertEquals(2, uidEntry.callCount);
-        // When sampling is enabled, cpu time is only measured for the first transaction in the
-        // sampling interval, for others an average duration of previous transactions is used as
-        // approximation
-        assertEquals(20, uidEntry.cpuTimeMicros);
-        sampledCallStatsList = sampledEntries.getCallStatsList();
-        assertEquals(1, sampledCallStatsList.size());
+        assertEquals(1, uidEntry.recordedCallCount);
+        assertEquals(10, uidEntry.cpuTimeMicros);
+        assertEquals(1, callStatsList.size());
 
         callSession = bcs.callStarted(binder, 2);
         bcs.time += 50;
         bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
         uidEntry = bcs.getUidEntries().get(TEST_UID);
         assertEquals(3, uidEntry.callCount);
-
-        // This is the first transaction of a new type, so the real CPU time will be measured
-        assertEquals(70, uidEntry.cpuTimeMicros);
-        sampledCallStatsList = sampledEntries.getCallStatsList();
-        assertEquals(2, sampledCallStatsList.size());
+        assertEquals(1, uidEntry.recordedCallCount);
+        // Still sampled even for another API.
+        callStatsList = uidEntry.getCallStatsList();
+        assertEquals(2, callStatsList.size());
     }
 
     @Test
@@ -116,10 +105,6 @@
         assertEquals(10, uidEntry.cpuTimeMicros);
         assertEquals(1, uidEntry.getCallStatsList().size());
 
-        BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
-        assertEquals("Sampling is not used when detailed tracking on",
-                0, bcs.getSampledEntries().getCallStatsList().size());
-
         List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
         assertEquals(1, callStatsList.get(0).callCount);
         assertEquals(10, callStatsList.get(0).cpuTimeMicros);
@@ -216,13 +201,57 @@
         BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
         Assert.assertNotNull(uidEntry);
         assertEquals(3, uidEntry.callCount);
-        assertEquals(70, uidEntry.cpuTimeMicros);
-        assertEquals("Detailed tracking off - no entries should be returned",
-                0, uidEntry.getCallStatsList().size());
+        assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros);
 
-        BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
-        List<BinderCallsStats.CallStat> sampledCallStatsList = sampledEntries.getCallStatsList();
-        assertEquals(1, sampledCallStatsList.size());
+        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
+        assertEquals(1, callStatsList.size());
+        BinderCallsStats.CallStat callStats = callStatsList.get(0);
+        assertEquals(3, callStats.callCount);
+        assertEquals(2, callStats.recordedCallCount);
+        assertEquals(60, callStats.cpuTimeMicros);
+        assertEquals(50, callStats.maxCpuTimeMicros);
+        assertEquals(0, callStats.maxRequestSizeBytes);
+        assertEquals(0, callStats.maxReplySizeBytes);
+    }
+
+    @Test
+    public void testSamplingWithDifferentApis() {
+        TestBinderCallsStats bcs = new TestBinderCallsStats();
+        bcs.setDetailedTracking(false);
+        bcs.setSamplingInterval(2);
+
+        Binder binder = new Binder();
+        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+        bcs.time += 10;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        callSession = bcs.callStarted(binder, 2 /* another method */);
+        bcs.time += 1000;  // shoud be ignored.
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+
+        SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+        assertEquals(1, uidEntries.size());
+        BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
+        assertEquals(2, uidEntry.callCount);
+        assertEquals(1, uidEntry.recordedCallCount);
+        assertEquals(10, uidEntry.cpuTimeMicros);
+
+        List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
+        assertEquals(2, callStatsList.size());
+
+        BinderCallsStats.CallStat callStats = callStatsList.get(0);
+        assertEquals(1, callStats.callCount);
+        assertEquals(1, callStats.recordedCallCount);
+        assertEquals(10, callStats.cpuTimeMicros);
+        assertEquals(10, callStats.maxCpuTimeMicros);
+
+        // Only call count should is tracked, rest is sampled.
+        callStats = callStatsList.get(1);
+        assertEquals(1, callStats.callCount);
+        assertEquals(0, callStats.recordedCallCount);
+        assertEquals(0, callStats.cpuTimeMicros);
+        assertEquals(0, callStats.maxCpuTimeMicros);
     }
 
     @Test
@@ -374,6 +403,7 @@
         assertEquals(20, stat.latencyMicros);
         assertEquals(20, stat.maxLatencyMicros);
         assertEquals(1, stat.callCount);
+        assertEquals(1, stat.recordedCallCount);
         assertEquals(REQUEST_SIZE, stat.maxRequestSizeBytes);
         assertEquals(REPLY_SIZE, stat.maxReplySizeBytes);
         assertEquals(0, stat.exceptionCount);
@@ -385,6 +415,14 @@
         long elapsedTime = 0;
 
         TestBinderCallsStats() {
+          // Make random generator not random.
+          super(new Random() {
+            int mCallCount = 0;
+
+            public int nextInt() {
+              return mCallCount++;
+            }
+          });
         }
 
         @Override
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index bac7a4d..1b15dbd 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -15,32 +15,38 @@
  */
 
 #include "CanvasTransform.h"
+#include "utils/Color.h"
 #include "Properties.h"
 
+#include <ui/ColorSpace.h>
 #include <SkColorFilter.h>
 #include <SkPaint.h>
-#include <log/log.h>
+
+#include <algorithm>
+#include <cmath>
 
 namespace android::uirenderer {
 
 static SkColor makeLight(SkColor color) {
-    SkScalar hsv[3];
-    SkColorToHSV(color, hsv);
-    if (hsv[1] > .2f) return color;
-    // hsv[1] *= .85f;
-    // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f);
-    hsv[2] = std::max(hsv[2], 1.1f - hsv[2]);
-    return SkHSVToColor(SkColorGetA(color), hsv);
+    Lab lab = sRGBToLab(color);
+    float invertedL = std::min(110 - lab.L, 100.0f);
+    if (invertedL > lab.L) {
+        lab.L = invertedL;
+        return LabToSRGB(lab, SkColorGetA(color));
+    } else {
+        return color;
+    }
 }
 
 static SkColor makeDark(SkColor color) {
-    SkScalar hsv[3];
-    SkColorToHSV(color, hsv);
-    if (hsv[1] > .2f) return color;
-    // hsv[1] *= .85f;
-    // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f);
-    hsv[2] = std::min(hsv[2], 1.1f - hsv[2]);
-    return SkHSVToColor(SkColorGetA(color), hsv);
+    Lab lab = sRGBToLab(color);
+    float invertedL = std::min(110 - lab.L, 100.0f);
+    if (invertedL < lab.L) {
+        lab.L = invertedL;
+        return LabToSRGB(lab, SkColorGetA(color));
+    } else {
+        return color;
+    }
 }
 
 static SkColor transformColor(ColorTransform transform, SkColor color) {
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 6408ce6..ab80d3d 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -286,7 +286,7 @@
         eglDestroySyncKHR(display, fence);
     }
 
-    return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
+    return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap)));
 }
 
 };  // namespace android::uirenderer
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index a401b3f..7a8d026 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -17,6 +17,7 @@
 
 #include "Caches.h"
 #include "HardwareBitmapUploader.h"
+#include "Properties.h"
 #include "renderthread/RenderProxy.h"
 #include "utils/Color.h"
 
@@ -34,6 +35,7 @@
 #include <SkToSRGBColorFilter.h>
 
 #include <limits>
+#include <SkHighContrastFilter.h>
 
 namespace android {
 
@@ -195,11 +197,13 @@
     mPixelStorage.ashmem.size = mappedSize;
 }
 
-Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
+Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette)
         : SkPixelRef(info.width(), info.height(), nullptr,
                      bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
         , mInfo(validateAlpha(info))
-        , mPixelStorageType(PixelStorageType::Hardware) {
+        , mPixelStorageType(PixelStorageType::Hardware)
+        , mPalette(palette)
+        , mPaletteGenerationId(getGenerationID()) {
     mPixelStorage.hardware.buffer = buffer;
     buffer->incStrong(buffer);
     setImmutable();  // HW bitmaps are always immutable
@@ -326,7 +330,106 @@
     if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) {
         *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
     }
+
+    // TODO: Move this to the canvas (or other?) layer where we have the target lightness
+    // mode and can selectively do the right thing.
+    if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) {
+        SkHighContrastConfig config;
+        config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
+        *outputColorFilter = SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter);
+    }
     return image;
 }
 
+class MinMaxAverage {
+public:
+
+    void add(float sample) {
+        if (mCount == 0) {
+            mMin = sample;
+            mMax = sample;
+        } else {
+            mMin = std::min(mMin, sample);
+            mMax = std::max(mMax, sample);
+        }
+        mTotal += sample;
+        mCount++;
+    }
+
+    float average() {
+        return mTotal / mCount;
+    }
+
+    float min() {
+        return mMin;
+    }
+
+    float max() {
+        return mMax;
+    }
+
+    float delta() {
+        return mMax - mMin;
+    }
+
+private:
+    float mMin = 0.0f;
+    float mMax = 0.0f;
+    float mTotal = 0.0f;
+    int mCount = 0;
+};
+
+BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
+    ATRACE_CALL();
+
+    SkPixmap pixmap{info, addr, rowBytes};
+
+    // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
+    // Experiment with something simpler since we just want to figure out if it's "color-ful"
+    // and then the average perceptual lightness.
+
+    MinMaxAverage hue, saturation, value;
+    int sampledCount = 0;
+
+    // Sample a grid of 100 pixels to get an overall estimation of the colors in play
+    const int x_step = std::max(1, pixmap.width() / 10);
+    const int y_step = std::max(1, pixmap.height() / 10);
+    for (int x = 0; x < pixmap.width(); x += x_step) {
+        for (int y = 0; y < pixmap.height(); y += y_step) {
+            SkColor color = pixmap.getColor(x, y);
+            if (!info.isOpaque() && SkColorGetA(color) < 75) {
+                continue;
+            }
+
+            sampledCount++;
+            float hsv[3];
+            SkColorToHSV(color, hsv);
+            hue.add(hsv[0]);
+            saturation.add(hsv[1]);
+            value.add(hsv[2]);
+        }
+    }
+
+    // TODO: Tune the coverage threshold
+    if (sampledCount < 5) {
+        ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
+              sampledCount, info.width(), info.height(), (int) info.colorType(), (int) info.alphaType());
+        return BitmapPalette::Unknown;
+    }
+
+    ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = %f]",
+          sampledCount,
+          hue.min(), hue.max(), hue.average(),
+          saturation.min(), saturation.max(), saturation.average());
+
+    if (hue.delta() <= 20 && saturation.delta() <= .1f) {
+        if (value.average() >= .5f) {
+            return BitmapPalette::Light;
+        } else {
+            return BitmapPalette::Dark;
+        }
+    }
+    return BitmapPalette::Unknown;
+}
+
 }  // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index dbd4456..d268042 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -34,6 +34,12 @@
     Hardware,
 };
 
+enum class BitmapPalette {
+    Unknown,
+    Light,
+    Dark,
+};
+
 namespace uirenderer {
 namespace renderthread {
 class RenderThread;
@@ -63,7 +69,7 @@
     Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
            size_t rowBytes);
     Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
-    Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
+    Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette = BitmapPalette::Unknown);
 
     int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); }
 
@@ -103,6 +109,20 @@
      */
     sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
 
+    static BitmapPalette computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes);
+
+    static BitmapPalette computePalette(const SkBitmap& bitmap) {
+        return computePalette(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes());
+    }
+
+    BitmapPalette palette() {
+        if (!isHardware() && mPaletteGenerationId != getGenerationID()) {
+            mPalette = computePalette(info(), pixels(), rowBytes());
+            mPaletteGenerationId = getGenerationID();
+        }
+        return mPalette;
+    }
+
 private:
     virtual ~Bitmap();
     void* getStorage() const;
@@ -111,6 +131,9 @@
 
     const PixelStorageType mPixelStorageType;
 
+    BitmapPalette mPalette = BitmapPalette::Unknown;
+    uint32_t mPaletteGenerationId = -1;
+
     bool mHasHardwareMipMap = false;
 
     union {
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 75740e8..a3e7859 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,8 +16,10 @@
 
 #include "Color.h"
 
-
 #include <utils/Log.h>
+#include <ui/ColorSpace.h>
+
+#include <algorithm>
 #include <cmath>
 
 namespace android {
@@ -107,5 +109,97 @@
     }
 }
 
+template<typename T>
+static constexpr T clamp(T x, T min, T max) {
+    return x < min ? min : x > max ? max : x;
+}
+
+//static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
+static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
+static const mat3 BRADFORD = mat3{
+        float3{ 0.8951f, -0.7502f,  0.0389f},
+        float3{ 0.2664f,  1.7135f, -0.0685f},
+        float3{-0.1614f,  0.0367f,  1.0296f}
+};
+
+static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const float3& dstWhitePoint) {
+    float3 srcLMS = matrix * srcWhitePoint;
+    float3 dstLMS = matrix * dstWhitePoint;
+    return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
+}
+
+namespace LabColorSpace {
+
+static constexpr float A = 216.0f / 24389.0f;
+static constexpr float B = 841.0f / 108.0f;
+static constexpr float C = 4.0f / 29.0f;
+static constexpr float D = 6.0f / 29.0f;
+
+float3 toXyz(const Lab& lab) {
+    float3 v { lab.L, lab.a, lab.b };
+    v[0] = clamp(v[0], 0.0f, 100.0f);
+    v[1] = clamp(v[1], -128.0f, 128.0f);
+    v[2] = clamp(v[2], -128.0f, 128.0f);
+
+    float fy = (v[0] + 16.0f) / 116.0f;
+    float fx = fy + (v[1] * 0.002f);
+    float fz = fy - (v[2] * 0.005f);
+    float X = fx > D ? fx * fx * fx : (1.0f / B) * (fx - C);
+    float Y = fy > D ? fy * fy * fy : (1.0f / B) * (fy - C);
+    float Z = fz > D ? fz * fz * fz : (1.0f / B) * (fz - C);
+
+    v[0] = X * ILLUMINANT_D50_XYZ[0];
+    v[1] = Y * ILLUMINANT_D50_XYZ[1];
+    v[2] = Z * ILLUMINANT_D50_XYZ[2];
+
+    return v;
+}
+
+Lab fromXyz(const float3& v) {
+    float X = v[0] / ILLUMINANT_D50_XYZ[0];
+    float Y = v[1] / ILLUMINANT_D50_XYZ[1];
+    float Z = v[2] / ILLUMINANT_D50_XYZ[2];
+
+    float fx = X > A ? pow(X, 1.0f / 3.0f) : B * X + C;
+    float fy = Y > A ? pow(Y, 1.0f / 3.0f) : B * Y + C;
+    float fz = Z > A ? pow(Z, 1.0f / 3.0f) : B * Z + C;
+
+    float L = 116.0f * fy - 16.0f;
+    float a = 500.0f * (fx - fy);
+    float b = 200.0f * (fy - fz);
+
+    return Lab {
+            clamp(L, 0.0f, 100.0f),
+            clamp(a, -128.0f, 128.0f),
+            clamp(b, -128.0f, 128.0f)
+    };
+}
+
+};
+
+Lab sRGBToLab(SkColor color) {
+    auto colorSpace = ColorSpace::sRGB();
+    float3 rgb;
+    rgb.r = SkColorGetR(color) / 255.0f;
+    rgb.g = SkColorGetG(color) / 255.0f;
+    rgb.b = SkColorGetB(color) / 255.0f;
+    float3 xyz = colorSpace.rgbToXYZ(rgb);
+    float3 srcXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1});
+    xyz = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * xyz;
+    return LabColorSpace::fromXyz(xyz);
+}
+
+SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) {
+    auto colorSpace = ColorSpace::sRGB();
+    float3 xyz = LabColorSpace::toXyz(lab);
+    float3 dstXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1});
+    xyz = adaptation(BRADFORD, ILLUMINANT_D50_XYZ, dstXYZ) * xyz;
+    float3 rgb = colorSpace.xyzToRGB(xyz);
+    return SkColorSetARGB(alpha,
+            static_cast<uint8_t>(rgb.r * 255),
+            static_cast<uint8_t>(rgb.g * 255),
+            static_cast<uint8_t>(rgb.b * 255));
+}
+
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 2bec1f5..3c13a54 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -114,6 +114,16 @@
 bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
 
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
+
+struct Lab {
+    float L;
+    float a;
+    float b;
+};
+
+Lab sRGBToLab(SkColor color);
+SkColor LabToSRGB(const Lab& lab, SkAlpha alpha);
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ee9e732..30a07ef 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -734,6 +734,11 @@
      * calling Activity. If a Looper is specified with a {@link LocationListener}
      * then callbacks are made on the supplied Looper thread.
      *
+     * <p> When location callbacks are invoked, the system will hold a wakelock
+     * on your application's behalf for some period of time, but not
+     * indefinitely. If your application requires a long running wakelock
+     * within the location callback, you should acquire it yourself.
+     *
      * <p class="note"> Prior to Jellybean, the minTime parameter was
      * only a hint, and some location provider implementations ignored it.
      * From Jellybean and onwards it is mandatory for Android compatible
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
deleted file mode 100644
index 95edc5e..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.drawer;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Pair;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settingslib.applications.InterestingConfigChanges;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-public class CategoryManager {
-
-    public static final String SETTING_PKG = "com.android.settings";
-
-    private static final String TAG = "CategoryManager";
-
-    private static CategoryManager sInstance;
-    private final InterestingConfigChanges mInterestingConfigChanges;
-
-    // Tile cache (key: <packageName, activityName>, value: tile)
-    private final Map<Pair<String, String>, Tile> mTileByComponentCache;
-
-    // Tile cache (key: category key, value: category)
-    private final Map<String, DashboardCategory> mCategoryByKeyMap;
-
-    private List<DashboardCategory> mCategories;
-    private String mExtraAction;
-
-    public static CategoryManager get(Context context) {
-        return get(context, null);
-    }
-
-    public static CategoryManager get(Context context, String action) {
-        if (sInstance == null) {
-            sInstance = new CategoryManager(context, action);
-        }
-        return sInstance;
-    }
-
-    CategoryManager(Context context, String action) {
-        mTileByComponentCache = new ArrayMap<>();
-        mCategoryByKeyMap = new ArrayMap<>();
-        mInterestingConfigChanges = new InterestingConfigChanges();
-        mInterestingConfigChanges.applyNewConfig(context.getResources());
-        mExtraAction = action;
-    }
-
-    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
-        tryInitCategories(context, SETTING_PKG);
-
-        return mCategoryByKeyMap.get(categoryKey);
-    }
-
-    public synchronized List<DashboardCategory> getCategories(Context context) {
-        tryInitCategories(context, SETTING_PKG);
-        return mCategories;
-    }
-
-    public synchronized void reloadAllCategories(Context context, String settingPkg) {
-        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
-                context.getResources());
-        mCategories = null;
-        tryInitCategories(context, forceClearCache, settingPkg);
-    }
-
-    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
-        if (mCategories == null) {
-            Log.w(TAG, "Category is null, skipping blacklist update");
-        }
-        for (int i = 0; i < mCategories.size(); i++) {
-            DashboardCategory category = mCategories.get(i);
-            for (int j = 0; j < category.getTilesCount(); j++) {
-                Tile tile = category.getTile(j);
-                if (tileBlacklist.contains(tile.intent.getComponent())) {
-                    category.removeTile(j--);
-                }
-            }
-        }
-    }
-
-    private synchronized void tryInitCategories(Context context, String settingPkg) {
-        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
-        // happens.
-        tryInitCategories(context, false /* forceClearCache */, settingPkg);
-    }
-
-    private synchronized void tryInitCategories(Context context, boolean forceClearCache,
-            String settingPkg) {
-        if (mCategories == null) {
-            if (forceClearCache) {
-                mTileByComponentCache.clear();
-            }
-            mCategoryByKeyMap.clear();
-            mCategories = TileUtils.getCategories(context, mTileByComponentCache,
-                    mExtraAction, settingPkg);
-            for (DashboardCategory category : mCategories) {
-                mCategoryByKeyMap.put(category.key, category);
-            }
-            backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
-            sortCategories(context, mCategoryByKeyMap);
-            filterDuplicateTiles(mCategoryByKeyMap);
-        }
-    }
-
-    @VisibleForTesting
-    synchronized void backwardCompatCleanupForCategory(
-            Map<Pair<String, String>, Tile> tileByComponentCache,
-            Map<String, DashboardCategory> categoryByKeyMap) {
-        // A package can use a) CategoryKey, b) old category keys, c) both.
-        // Check if a package uses old category key only.
-        // If yes, map them to new category key.
-
-        // Build a package name -> tile map first.
-        final Map<String, List<Tile>> packageToTileMap = new HashMap<>();
-        for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) {
-            final String packageName = tileEntry.getKey().first;
-            List<Tile> tiles = packageToTileMap.get(packageName);
-            if (tiles == null) {
-                tiles = new ArrayList<>();
-                packageToTileMap.put(packageName, tiles);
-            }
-            tiles.add(tileEntry.getValue());
-        }
-
-        for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) {
-            final List<Tile> tiles = entry.getValue();
-            // Loop map, find if all tiles from same package uses old key only.
-            boolean useNewKey = false;
-            boolean useOldKey = false;
-            for (Tile tile : tiles) {
-                if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) {
-                    useOldKey = true;
-                } else {
-                    useNewKey = true;
-                    break;
-                }
-            }
-            // Uses only old key, map them to new keys one by one.
-            if (useOldKey && !useNewKey) {
-                for (Tile tile : tiles) {
-                    final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category);
-                    tile.category = newCategoryKey;
-                    // move tile to new category.
-                    DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey);
-                    if (newCategory == null) {
-                        newCategory = new DashboardCategory();
-                        categoryByKeyMap.put(newCategoryKey, newCategory);
-                    }
-                    newCategory.addTile(tile);
-                }
-            }
-        }
-    }
-
-    /**
-     * Sort the tiles injected from all apps such that if they have the same priority value,
-     * they wil lbe sorted by package name.
-     * <p/>
-     * A list of tiles are considered sorted when their priority value decreases in a linear
-     * scan.
-     */
-    @VisibleForTesting
-    synchronized void sortCategories(Context context,
-            Map<String, DashboardCategory> categoryByKeyMap) {
-        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
-            categoryEntry.getValue().sortTiles(context.getPackageName());
-        }
-    }
-
-    /**
-     * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the
-     * same intent.
-     */
-    @VisibleForTesting
-    synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
-        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
-            final DashboardCategory category = categoryEntry.getValue();
-            final int count = category.getTilesCount();
-            final Set<ComponentName> components = new ArraySet<>();
-            for (int i = count - 1; i >= 0; i--) {
-                final Tile tile = category.getTile(i);
-                if (tile.intent == null) {
-                    continue;
-                }
-                final ComponentName tileComponent = tile.intent.getComponent();
-                if (components.contains(tileComponent)) {
-                    category.removeTile(i);
-                } else {
-                    components.add(tileComponent);
-                }
-            }
-        }
-    }
-
-    /**
-     * Sort priority value for tiles within a single {@code DashboardCategory}.
-     *
-     * @see #sortCategories(Context, Map)
-     */
-    private synchronized void sortCategoriesForExternalTiles(Context context,
-            DashboardCategory dashboardCategory) {
-        dashboardCategory.sortTiles(context.getPackageName());
-
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index f54ba8c..06f1456 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -35,6 +35,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.annotation.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -48,6 +50,8 @@
     private static final boolean DEBUG_TIMING = false;
 
     private static final String LOG_TAG = "TileUtils";
+    @VisibleForTesting
+    static final String SETTING_PKG = "com.android.settings";
 
     /**
      * Settings will search for system activities of this action and add them as a top level
@@ -200,7 +204,7 @@
      * categories
      */
     public static List<DashboardCategory> getCategories(Context context,
-            Map<Pair<String, String>, Tile> cache, String extraAction, String settingPkg) {
+            Map<Pair<String, String>, Tile> cache, String extraAction) {
         final long startTime = System.currentTimeMillis();
         boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
                 != 0;
@@ -210,22 +214,18 @@
             // TODO: Needs much optimization, too many PM queries going on here.
             if (user.getIdentifier() == ActivityManager.getCurrentUser()) {
                 // Only add Settings for this user.
-                getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true,
-                        settingPkg);
+                getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true);
                 getTilesForAction(context, user, OPERATOR_SETTINGS, cache,
-                        OPERATOR_DEFAULT_CATEGORY, tiles, false, true, settingPkg);
+                        OPERATOR_DEFAULT_CATEGORY, tiles, false, true);
                 getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache,
-                        MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true, settingPkg);
+                        MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true);
             }
             if (setup) {
-                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false,
-                        settingPkg);
-                    getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false,
-                            settingPkg);
-                    if (extraAction != null) {
-                        getTilesForAction(context, user, extraAction, cache, null, tiles, false,
-                                settingPkg);
-                    }
+                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
+                getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false);
+                if (extraAction != null) {
+                    getTilesForAction(context, user, extraAction, cache, null, tiles, false);
+                }
             }
         }
 
@@ -256,19 +256,18 @@
 
     private static void getTilesForAction(Context context,
             UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
-            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings,
-            String settingPkg) {
+            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) {
         getTilesForAction(context, user, action, addedCache, defaultCategory, outTiles,
-                requireSettings, requireSettings, settingPkg);
+                requireSettings, requireSettings);
     }
 
     private static void getTilesForAction(Context context,
             UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
             String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings,
-            boolean usePriority, String settingPkg) {
+            boolean usePriority) {
         Intent intent = new Intent(action);
         if (requireSettings) {
-            intent.setPackage(settingPkg);
+            intent.setPackage(SETTING_PKG);
         }
         getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
                 usePriority, true, true);
@@ -281,7 +280,6 @@
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
-        Map<String, IContentProvider> providerMap = new HashMap<>();
         for (ResolveInfo resolved : results) {
             if (!resolved.system) {
                 // Do not allow any app to add to settings, only system ones.
@@ -312,7 +310,7 @@
                 tile.priority = usePriority ? resolved.priority : 0;
                 tile.metaData = activityInfo.metaData;
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
-                        pm, providerMap, forceTintExternalIcon);
+                        pm, forceTintExternalIcon);
                 if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
                 addedCache.put(key, tile);
             }
@@ -328,11 +326,10 @@
 
     private static boolean updateTileData(Context context, Tile tile,
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm,
-            Map<String, IContentProvider> providerMap, boolean forceTintExternalIcon) {
+            boolean forceTintExternalIcon) {
         if (applicationInfo.isSystemApp()) {
             boolean forceTintIcon = false;
             int icon = 0;
-            Pair<String, Integer> iconFromUri = null;
             CharSequence title = null;
             String summary = null;
             String keyHint = null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
index 92044c3..7ed357c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
@@ -36,7 +36,8 @@
             "/system/etc/NOTICE.xml.gz",
             "/vendor/etc/NOTICE.xml.gz",
             "/odm/etc/NOTICE.xml.gz",
-            "/oem/etc/NOTICE.xml.gz"};
+            "/oem/etc/NOTICE.xml.gz",
+            "/product/etc/NOTICE.xml.gz"};
     private static final String NOTICE_HTML_FILE_NAME = "NOTICE.html";
 
     private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
deleted file mode 100644
index 4efcb7e..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.drawer;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Pair;
-
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.shadows.ShadowApplication;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-public class CategoryManagerTest {
-
-    private Context mContext;
-    private CategoryManager mCategoryManager;
-    private Map<Pair<String, String>, Tile> mTileByComponentCache;
-    private Map<String, DashboardCategory> mCategoryByKeyMap;
-
-    @Before
-    public void setUp() {
-        mContext = ShadowApplication.getInstance().getApplicationContext();
-        mTileByComponentCache = new HashMap<>();
-        mCategoryByKeyMap = new HashMap<>();
-        mCategoryManager = CategoryManager.get(mContext);
-    }
-
-    @Test
-    public void getInstance_shouldBeSingleton() {
-        assertThat(mCategoryManager).isSameAs(CategoryManager.get(mContext));
-    }
-
-    @Test
-    public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForNewKeys() {
-        final Tile tile1 = new Tile();
-        final Tile tile2 = new Tile();
-        tile1.category = CategoryKey.CATEGORY_ACCOUNT;
-        tile2.category = CategoryKey.CATEGORY_ACCOUNT;
-        final DashboardCategory category = new DashboardCategory();
-        category.addTile(tile1);
-        category.addTile(tile2);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category);
-        mTileByComponentCache.put(new Pair<>("PACKAGE", "1"), tile1);
-        mTileByComponentCache.put(new Pair<>("PACKAGE", "2"), tile2);
-
-        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
-
-        assertThat(mCategoryByKeyMap.size()).isEqualTo(1);
-        assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT)).isNotNull();
-    }
-
-    @Test
-    public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForMixedKeys() {
-        final Tile tile1 = new Tile();
-        final Tile tile2 = new Tile();
-        final String oldCategory = "com.android.settings.category.wireless";
-        tile1.category = CategoryKey.CATEGORY_ACCOUNT;
-        tile2.category = oldCategory;
-        final DashboardCategory category1 = new DashboardCategory();
-        category1.addTile(tile1);
-        final DashboardCategory category2 = new DashboardCategory();
-        category2.addTile(tile2);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category1);
-        mCategoryByKeyMap.put(oldCategory, category2);
-        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
-        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tile2);
-
-        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
-
-        assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
-        assertThat(
-                mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).getTilesCount()).isEqualTo(1);
-        assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void backwardCompatCleanupForCategory_shouldChangeCategoryForOldKeys() {
-        final Tile tile1 = new Tile();
-        final String oldCategory = "com.android.settings.category.wireless";
-        tile1.category = oldCategory;
-        final DashboardCategory category1 = new DashboardCategory();
-        category1.addTile(tile1);
-        mCategoryByKeyMap.put(oldCategory, category1);
-        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
-
-        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
-
-        // Added 1 more category to category map.
-        assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
-        // The new category map has CATEGORY_NETWORK type now, which contains 1 tile.
-        assertThat(
-                mCategoryByKeyMap.get(CategoryKey.CATEGORY_NETWORK).getTilesCount()).isEqualTo(1);
-        // Old category still exists.
-        assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void sortCategories_singlePackage_shouldReorderBasedOnPriority() {
-        // Create some fake tiles that are not sorted.
-        final String testPackage = "com.android.test";
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile1.priority = 100;
-        final Tile tile2 = new Tile();
-        tile2.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class2"));
-        tile2.priority = 50;
-        final Tile tile3 = new Tile();
-        tile3.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class3"));
-        tile3.priority = 200;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        // Sort their priorities
-        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
-                mCategoryByKeyMap);
-
-        // Verify they are now sorted.
-        assertThat(category.getTile(0)).isSameAs(tile3);
-        assertThat(category.getTile(1)).isSameAs(tile1);
-        assertThat(category.getTile(2)).isSameAs(tile2);
-    }
-
-    @Test
-    public void sortCategories_multiPackage_shouldReorderBasedOnPackageAndPriority() {
-        // Create some fake tiles that are not sorted.
-        final String testPackage1 = "com.android.test1";
-        final String testPackage2 = "com.android.test2";
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent =
-                new Intent().setComponent(new ComponentName(testPackage2, "class1"));
-        tile1.priority = 100;
-        final Tile tile2 = new Tile();
-        tile2.intent =
-                new Intent().setComponent(new ComponentName(testPackage1, "class2"));
-        tile2.priority = 100;
-        final Tile tile3 = new Tile();
-        tile3.intent =
-                new Intent().setComponent(new ComponentName(testPackage1, "class3"));
-        tile3.priority = 50;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        // Sort their priorities
-        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
-                mCategoryByKeyMap);
-
-        // Verify they are now sorted.
-        assertThat(category.getTile(0)).isSameAs(tile2);
-        assertThat(category.getTile(1)).isSameAs(tile1);
-        assertThat(category.getTile(2)).isSameAs(tile3);
-    }
-
-    @Test
-    public void sortCategories_internalPackageTiles_shouldSkipTileForInternalPackage() {
-        // Create some fake tiles that are not sorted.
-        final String testPackage =
-                ShadowApplication.getInstance().getApplicationContext().getPackageName();
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile1.priority = 100;
-        final Tile tile2 = new Tile();
-        tile2.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class2"));
-        tile2.priority = 100;
-        final Tile tile3 = new Tile();
-        tile3.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class3"));
-        tile3.priority = 50;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        // Sort their priorities
-        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
-                mCategoryByKeyMap);
-
-        // Verify the sorting order is not changed
-        assertThat(category.getTile(0)).isSameAs(tile1);
-        assertThat(category.getTile(1)).isSameAs(tile2);
-        assertThat(category.getTile(2)).isSameAs(tile3);
-    }
-
-    @Test
-    public void sortCategories_internalAndExternalPackageTiles_shouldRetainPriorityOrdering() {
-        // Inject one external tile among internal tiles.
-        final String testPackage =
-            ShadowApplication.getInstance().getApplicationContext().getPackageName();
-        final String testPackage2 = "com.google.test2";
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent = new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile1.priority = 2;
-        final Tile tile2 = new Tile();
-        tile2.intent = new Intent().setComponent(new ComponentName(testPackage, "class2"));
-        tile2.priority = 1;
-        final Tile tile3 = new Tile();
-        tile3.intent = new Intent().setComponent(new ComponentName(testPackage2, "class0"));
-        tile3.priority = 0;
-        final Tile tile4 = new Tile();
-        tile4.intent = new Intent().setComponent(new ComponentName(testPackage, "class3"));
-        tile4.priority = -1;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        category.addTile(tile4);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        // Sort their priorities
-        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
-            mCategoryByKeyMap);
-
-        // Verify the sorting order is not changed
-        assertThat(category.getTile(0)).isSameAs(tile1);
-        assertThat(category.getTile(1)).isSameAs(tile2);
-        assertThat(category.getTile(2)).isSameAs(tile3);
-        assertThat(category.getTile(3)).isSameAs(tile4);
-    }
-
-    @Test
-    public void sortCategories_samePriority_internalPackageTileShouldTakePrecedence() {
-        // Inject one external tile among internal tiles with same priority.
-        final String testPackage =
-            ShadowApplication.getInstance().getApplicationContext().getPackageName();
-        final String testPackage2 = "com.google.test2";
-        final String testPackage3 = "com.abcde.test3";
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent = new Intent().setComponent(new ComponentName(testPackage2, "class1"));
-        tile1.priority = 1;
-        final Tile tile2 = new Tile();
-        tile2.intent = new Intent().setComponent(new ComponentName(testPackage, "class2"));
-        tile2.priority = 1;
-        final Tile tile3 = new Tile();
-        tile3.intent = new Intent().setComponent(new ComponentName(testPackage3, "class3"));
-        tile3.priority = 1;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        // Sort their priorities
-        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
-            mCategoryByKeyMap);
-
-        // Verify the sorting order is internal first, follow by package name ordering
-        assertThat(category.getTile(0)).isSameAs(tile2);
-        assertThat(category.getTile(1)).isSameAs(tile3);
-        assertThat(category.getTile(2)).isSameAs(tile1);
-    }
-
-    @Test
-    public void filterTiles_noDuplicate_noChange() {
-        // Create some unique tiles
-        final String testPackage =
-                ShadowApplication.getInstance().getApplicationContext().getPackageName();
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile1.priority = 100;
-        final Tile tile2 = new Tile();
-        tile2.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class2"));
-        tile2.priority = 100;
-        final Tile tile3 = new Tile();
-        tile3.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class3"));
-        tile3.priority = 50;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
-
-        assertThat(category.getTilesCount()).isEqualTo(3);
-    }
-
-    @Test
-    public void filterTiles_hasDuplicate_shouldOnlyKeepUniqueTiles() {
-        // Create tiles pointing to same intent.
-        final String testPackage =
-                ShadowApplication.getInstance().getApplicationContext().getPackageName();
-        final DashboardCategory category = new DashboardCategory();
-        final Tile tile1 = new Tile();
-        tile1.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile1.priority = 100;
-        final Tile tile2 = new Tile();
-        tile2.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile2.priority = 100;
-        final Tile tile3 = new Tile();
-        tile3.intent =
-                new Intent().setComponent(new ComponentName(testPackage, "class1"));
-        tile3.priority = 50;
-        category.addTile(tile1);
-        category.addTile(tile2);
-        category.addTile(tile3);
-        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
-
-        mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
-
-        assertThat(category.getTilesCount()).isEqualTo(1);
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 31621af..a1c48f0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -177,8 +177,7 @@
                 event -> testAction.equals(event.getAction())), anyInt(), anyInt()))
                 .thenReturn(info);
 
-        List<DashboardCategory> categoryList = TileUtils.getCategories(
-                mContext, cache, testAction, CategoryManager.SETTING_PKG);
+        List<DashboardCategory> categoryList = TileUtils.getCategories(mContext, cache, testAction);
         assertThat(categoryList.get(0).getTile(0).category).isEqualTo(testCategory);
     }
 
@@ -193,12 +192,12 @@
         userHandleList.add(new UserHandle(ActivityManager.getCurrentUser()));
         when(mUserManager.getUserProfiles()).thenReturn(userHandleList);
 
-        TileUtils.getCategories(mContext, cache, null /* action */, CategoryManager.SETTING_PKG);
+        TileUtils.getCategories(mContext, cache, null /* action */);
         verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser(
                 intentCaptor.capture(), anyInt(), anyInt());
 
         assertThat(intentCaptor.getAllValues().get(0).getPackage())
-                .isEqualTo(CategoryManager.SETTING_PKG);
+                .isEqualTo(TileUtils.SETTING_PKG);
     }
 
     @Test
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 2a22bf2..38d266d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -154,12 +154,11 @@
     }
 
     public void fadeInTranslating() {
-        float translation = mShelfIcons.getTranslationY();
-        mShelfIcons.setTranslationY(translation - mShelfAppearTranslation);
+        mShelfIcons.setTranslationY(-mShelfAppearTranslation);
         mShelfIcons.setAlpha(0);
         mShelfIcons.animate()
                 .setInterpolator(Interpolators.DECELERATE_QUINT)
-                .translationY(translation)
+                .translationY(0)
                 .setDuration(SHELF_IN_TRANSLATION_DURATION)
                 .start();
         mShelfIcons.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index e804460..4df1e3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -118,7 +118,7 @@
                     mPanel.startExpandingFromPeek();
                     // This call needs to be after the expansion start otherwise we will get a
                     // flicker of one frame as it's not expanded yet.
-                    mHeadsUpManager.unpinAll();
+                    mHeadsUpManager.unpinAll(true);
                     mPanel.clearNotificationEffects();
                     endMotion();
                     return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 6694b93a3..677dd73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -389,13 +389,23 @@
 
     /**
      * Unpins all pinned Heads Up Notifications.
+     * @param userUnPinned The unpinned action is trigger by user real operation.
      */
-    public void unpinAll() {
+    public void unpinAll(boolean userUnPinned) {
         for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
             setEntryPinned(entry, false /* isPinned */);
             // maybe it got un sticky
             entry.updateEntry(false /* updatePostTime */);
+
+            // when the user unpinned all of HUNs by moving one HUN, all of HUNs should not stay
+            // on the screen.
+            if (userUnPinned && entry.entry != null && entry.entry.row != null) {
+                ExpandableNotificationRow row = entry.entry.row;
+                if (row.mustStayOnScreen()) {
+                    row.setHeadsUpIsVisible();
+                }
+            }
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 65ad596..ad80cc26 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -123,8 +123,7 @@
     }
 
     public void destroy() {
-        mHandler.sendMessage(obtainMessage(
-                RemoteFillService::handleDestroy, this));
+        mHandler.sendMessage(obtainMessage(RemoteFillService::handleDestroy, this));
     }
 
     private void handleDestroy() {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 18255c5..8f59ca9 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -839,7 +839,8 @@
     // FillServiceCallbacks
     @Override
     public void onServiceDied(RemoteFillService service) {
-        // TODO(b/337565347): implement
+        Slog.w(TAG, "removing session because service died");
+        forceRemoveSelfLocked();
     }
 
     // AutoFillUiCallback
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 74d8755..9631e46 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2271,6 +2271,7 @@
         return ruleName;
     }
 
+    @GuardedBy("mRulesLock")
     private @NonNull SparseIntArray getUidFirewallRulesLR(int chain) {
         switch (chain) {
             case FIREWALL_CHAIN_STANDBY:
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 17257ee..91942a5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3332,6 +3332,14 @@
             // Turn this condition on to cause killing to happen regularly, for testing.
             if (proc.baseProcessTracker != null) {
                 proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
+                for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                    ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+                    StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
+                            proc.info.uid,
+                            holder.state.getName(),
+                            holder.state.getPackage(),
+                            proc.lastCachedPss, holder.appVersion);
+                }
             }
             proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
         } else if (proc != null && !keepIfLarge
@@ -3341,6 +3349,14 @@
             if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
                 if (proc.baseProcessTracker != null) {
                     proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
+                    for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                        ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+                        StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
+                                proc.info.uid,
+                                holder.state.getName(),
+                                holder.state.getPackage(),
+                                proc.lastCachedPss, holder.appVersion);
+                    }
                 }
                 proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
             }
@@ -5365,6 +5381,19 @@
                                 infos[i].getTotalUss(), infos[i].getTotalRss(), false,
                                 ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime-startTime,
                                 proc.pkgList.mPkgList);
+                        for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                            ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+                            StatsLog.write(StatsLog.PROCESS_MEMORY_STAT_REPORTED,
+                                    proc.info.uid,
+                                    holder.state.getName(),
+                                    holder.state.getPackage(),
+                                    infos[i].getTotalPss(),
+                                    infos[i].getTotalUss(),
+                                    infos[i].getTotalRss(),
+                                    ProcessStats.ADD_PSS_EXTERNAL_SLOW,
+                                    endTime-startTime,
+                                    holder.appVersion);
+                        }
                     }
                 }
             }
@@ -5395,6 +5424,16 @@
                         // Record this for posterity if the process has been stable.
                         proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false,
                                 ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList.mPkgList);
+                        for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                            ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+                            StatsLog.write(StatsLog.PROCESS_MEMORY_STAT_REPORTED,
+                                    proc.info.uid,
+                                    holder.state.getName(),
+                                    holder.state.getPackage(),
+                                    pss[i], tmpUss[0], tmpUss[2],
+                                    ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime,
+                                    holder.appVersion);
+                        }
                     }
                 }
             }
@@ -15232,6 +15271,16 @@
                         // Record this for posterity if the process has been stable.
                         r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
                                 reportType, endTime-startTime, r.pkgList.mPkgList);
+                        for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                            ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg);
+                            StatsLog.write(StatsLog.PROCESS_MEMORY_STAT_REPORTED,
+                                    r.info.uid,
+                                    holder.state.getName(),
+                                    holder.state.getPackage(),
+                                    myTotalPss, myTotalUss, myTotalRss, reportType,
+                                    endTime-startTime,
+                                    holder.appVersion);
+                        }
                     }
                 }
 
@@ -15730,6 +15779,15 @@
                     // Record this for posterity if the process has been stable.
                     r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
                             reportType, endTime-startTime, r.pkgList.mPkgList);
+                    for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                        ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg);
+                        StatsLog.write(StatsLog.PROCESS_MEMORY_STAT_REPORTED,
+                                r.info.uid,
+                                holder.state.getName(),
+                                holder.state.getPackage(),
+                                myTotalPss, myTotalUss, myTotalRss, reportType, endTime-startTime,
+                                holder.appVersion);
+                    }
                 }
             }
 
@@ -19759,6 +19817,15 @@
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(
                 pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList);
+        for (int ipkg = proc.pkgList.mPkgList.size() - 1; ipkg >= 0; ipkg--) {
+            ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+            StatsLog.write(StatsLog.PROCESS_MEMORY_STAT_REPORTED,
+                    proc.info.uid,
+                    holder.state.getName(),
+                    holder.state.getPackage(),
+                    pss, uss, rss, statType, pssDuration,
+                    holder.appVersion);
+        }
         if (DEBUG_PSS) Slog.d(TAG_PSS,
                 "pss of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
                 + " state=" + ProcessList.makeProcStateString(procState));
@@ -20110,6 +20177,14 @@
                         app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
                                 + " dur=" + checkDur + " limit=" + cpuLimit, true);
                         app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList);
+                        for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                            ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg);
+                            StatsLog.write(StatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
+                                    app.info.uid,
+                                    holder.state.getName(),
+                                    holder.state.getPackage(),
+                                    holder.appVersion);
+                        }
                     }
                 }
                 app.lastCpuTime = app.curCpuTime;
@@ -20945,6 +21020,7 @@
         }
         if (memFactor != mLastMemoryLevel) {
             EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);
+            StatsLog.write(StatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor);
         }
         mLastMemoryLevel = memFactor;
         mLastNumProcesses = mLruProcesses.size();
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index dbade5f..de732c7 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -4676,6 +4676,8 @@
             // will wake up stacks or put them to sleep as appropriate.
             if (wasSleeping) {
                 mSleeping = false;
+                StatsLog.write(StatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED,
+                        StatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED__STATE__AWAKE);
                 startTimeTrackingFocusedActivityLocked();
                 mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
                 mStackSupervisor.comeOutOfSleepIfNeededLocked();
@@ -4686,6 +4688,8 @@
             }
         } else if (!mSleeping && shouldSleep) {
             mSleeping = true;
+            StatsLog.write(StatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED,
+                    StatsLog.ACTIVITY_MANAGER_SLEEP_STATE_CHANGED__STATE__ASLEEP);
             if (mCurAppTimeTracker != null) {
                 mCurAppTimeTracker.stop();
             }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index d9a8818..2541352 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.am;
 
+import static android.net.wifi.WifiManager.WIFI_FEATURE_LINK_LAYER_STATS;
+
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothAdapter;
@@ -410,8 +412,11 @@
 
             if (mWifiManager != null) {
                 try {
-                    wifiReceiver = new SynchronousResultReceiver("wifi");
-                    mWifiManager.requestActivityInfo(wifiReceiver);
+                    // Only fetch WiFi power data if it is supported.
+                    if ((mWifiManager.getSupportedFeatures() & WIFI_FEATURE_LINK_LAYER_STATS) != 0) {
+                        wifiReceiver = new SynchronousResultReceiver("wifi");
+                        mWifiManager.requestActivityInfo(wifiReceiver);
+                    }
                 } catch (RemoteException e) {
                     // Oh well.
                 }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 211b8ff..b33ce2b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -43,6 +43,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -538,6 +539,12 @@
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
+                for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                    StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
+                            uid, processName, pkgList.keyAt(ipkg),
+                            ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+                            pkgList.valueAt(ipkg).appVersion);
+                }
                 origBase.makeInactive();
             }
             baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
@@ -567,6 +574,12 @@
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
+                for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                    StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
+                            uid, processName, pkgList.keyAt(ipkg),
+                            ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+                            pkgList.valueAt(ipkg).appVersion);
+                }
                 origBase.makeInactive();
             }
             baseProcessTracker = null;
@@ -829,6 +842,12 @@
     public void forceProcessStateUpTo(int newState) {
         if (mRepProcState > newState) {
             curProcState = mRepProcState = newState;
+            for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
+                        uid, processName, pkgList.keyAt(ipkg),
+                        ActivityManager.processStateAmToProto(mRepProcState),
+                        pkgList.valueAt(ipkg).appVersion);
+            }
         }
     }
 
@@ -841,6 +860,12 @@
             long now = SystemClock.uptimeMillis();
             baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
                     tracker.getMemFactorLocked(), now, pkgList.mPkgList);
+            for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+                StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
+                        uid, processName, pkgList.keyAt(ipkg),
+                        ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+                        pkgList.valueAt(ipkg).appVersion);
+            }
             if (N != 1) {
                 for (int i=0; i<N; i++) {
                     ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
@@ -892,6 +917,12 @@
 
     void setReportedProcState(int repProcState) {
         mRepProcState = repProcState;
+        for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+            StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
+                    uid, processName, pkgList.keyAt(ipkg),
+                    ActivityManager.processStateAmToProto(mRepProcState),
+                    pkgList.valueAt(ipkg).appVersion);
+        }
         mWindowProcessController.setReportedProcState(repProcState);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 7ba8e14..b796abd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -66,11 +66,7 @@
                     Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
                     mSystemAudioActivated ? "true" : "false");
         }
-        if (setSystemAudioMode(false)) {
-            mService.sendCecCommand(
-                    HdmiCecMessageBuilder.buildSetSystemAudioMode(
-                            mAddress, Constants.ADDR_BROADCAST, false));
-        }
+        terminateSystemAudioMode();
     }
 
     @Override
@@ -102,6 +98,18 @@
         }
     }
 
+    @ServiceThreadOnly
+    protected boolean handleActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int logicalAddress = message.getSource();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
+        if (!mActiveSource.equals(activeSource)) {
+            setActiveSource(activeSource);
+        }
+        return true;
+    }
+
     @Override
     @ServiceThreadOnly
     protected int getPreferredAddress() {
@@ -320,6 +328,21 @@
         }
     }
 
+    protected void terminateSystemAudioMode() {
+        // remove pending initiation actions
+        removeAction(SystemAudioInitiationActionFromAvr.class);
+        if (!isSystemAudioActivated()) {
+            return;
+        }
+
+        if (setSystemAudioMode(false)) {
+            // send <Set System Audio Mode> [“Off”]
+            mService.sendCecCommand(
+                    HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                            mAddress, Constants.ADDR_BROADCAST, false));
+        }
+    }
+
     /** Reports if System Audio Mode is supported by the connected TV */
     interface TvSystemAudioModeSupportedCallback {
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ebb3209..76f9695 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -628,6 +628,7 @@
         mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updatePowerSaveWhitelistUL() {
         try {
             int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle();
@@ -654,6 +655,7 @@
      *
      * @return whether any uid has been whitelisted.
      */
+    @GuardedBy("mUidRulesFirstLock")
     boolean addDefaultRestrictBackgroundWhitelistUidsUL() {
         final List<UserInfo> users = mUserManager.getUsers();
         final int numberUsers = users.size();
@@ -666,6 +668,7 @@
         return changed;
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private boolean addDefaultRestrictBackgroundWhitelistUidsUL(int userId) {
         final SystemConfig sysConfig = SystemConfig.getInstance();
         final PackageManager pm = mContext.getPackageManager();
@@ -1120,6 +1123,7 @@
      * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
      * to show visible notifications as needed.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     void updateNotificationsNL() {
         if (LOGV) Slog.v(TAG, "updateNotificationsNL()");
         Trace.traceBegin(TRACE_TAG_NETWORK, "updateNotificationsNL");
@@ -1266,6 +1270,7 @@
      * @return relevant subId, or {@link #INVALID_SUBSCRIPTION_ID} when no
      *         matching subId found.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private int findRelevantSubIdNL(NetworkTemplate template) {
         // Mobile template is relevant when any active subscriber matches
         for (int i = 0; i < mSubIdToSubscriberId.size(); i++) {
@@ -1285,6 +1290,7 @@
      * Notify that given {@link NetworkTemplate} is over
      * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private void notifyOverLimitNL(NetworkTemplate template) {
         if (!mOverLimitNotified.contains(template)) {
             mContext.startActivity(buildNetworkOverLimitIntent(mContext.getResources(), template));
@@ -1292,6 +1298,7 @@
         }
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private void notifyUnderLimitNL(NetworkTemplate template) {
         mOverLimitNotified.remove(template);
     }
@@ -1462,6 +1469,7 @@
      * @param subId that has its associated NetworkPolicy updated if necessary
      * @return if any policies were updated
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private boolean maybeUpdateMobilePolicyCycleAL(int subId, String subscriberId) {
         if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleAL()");
 
@@ -1619,6 +1627,7 @@
      * @param shouldNormalizePolicies true iff network policies need to be normalized after the
      *                                update.
      */
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
     void handleNetworkPoliciesUpdateAL(boolean shouldNormalizePolicies) {
         if (shouldNormalizePolicies) {
             normalizePoliciesNL();
@@ -1633,6 +1642,7 @@
      * Proactively control network data connections when they exceed
      * {@link NetworkPolicy#limitBytes}.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     void updateNetworkEnabledNL() {
         if (LOGV) Slog.v(TAG, "updateNetworkEnabledNL()");
         Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkEnabledNL");
@@ -1773,6 +1783,7 @@
      * {@link NetworkPolicy} that need to be enforced. When matches found, set
      * remaining quota based on usage cycle and historical stats.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     void updateNetworkRulesNL() {
         if (LOGV) Slog.v(TAG, "updateNetworkRulesNL()");
         Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkRulesNL");
@@ -1957,6 +1968,7 @@
      * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
      * have at least a default mobile policy defined.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private void ensureActiveMobilePolicyAL() {
         if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyAL()");
         if (mSuppressDefaultPolicy) return;
@@ -1977,6 +1989,7 @@
      * @param subscriberId that we check for an existing policy
      * @return true if a mobile network policy was added, or false one already existed.
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) {
         // Poke around to see if we already have a policy
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
@@ -2036,6 +2049,7 @@
      *
      * @return if the policy was modified
      */
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private boolean updateDefaultMobilePolicyAL(int subId, NetworkPolicy policy) {
         if (!policy.inferred) {
             if (LOGD) Slog.d(TAG, "Ignoring user-defined policy " + policy);
@@ -2091,6 +2105,7 @@
         }
     }
 
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
     private void readPolicyAL() {
         if (LOGV) Slog.v(TAG, "readPolicyAL()");
 
@@ -2322,6 +2337,7 @@
      * Perform upgrade step of moving any user-defined meterness overrides over
      * into {@link WifiConfiguration}.
      */
+    @GuardedBy({"mNetworkPoliciesSecondLock", "mUidRulesFirstLock"})
     private void upgradeWifiMeteredOverrideAL() {
         boolean modified = false;
         final WifiManager wm = mContext.getSystemService(WifiManager.class);
@@ -2352,6 +2368,7 @@
         }
     }
 
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
     void writePolicyAL() {
         if (LOGV) Slog.v(TAG, "writePolicyAL()");
 
@@ -2523,6 +2540,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void setUidPolicyUncheckedUL(int uid, int oldPolicy, int policy, boolean persist) {
         setUidPolicyUncheckedUL(uid, policy, false);
 
@@ -2554,6 +2572,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void setUidPolicyUncheckedUL(int uid, int policy, boolean persist) {
         if (policy == POLICY_NONE) {
             mUidPolicy.delete(uid);
@@ -2601,6 +2620,7 @@
      * Removes any persistable state associated with given {@link UserHandle}, persisting
      * if any changes that are made.
      */
+    @GuardedBy("mUidRulesFirstLock")
     boolean removeUserStateUL(int userId, boolean writePolicy) {
 
         mLogger.removingUserState(userId);
@@ -2702,10 +2722,12 @@
         }
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private void normalizePoliciesNL() {
         normalizePoliciesNL(getNetworkPolicies(mContext.getOpPackageName()));
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private void normalizePoliciesNL(NetworkPolicy[] policies) {
         mNetworkPolicy.clear();
         for (NetworkPolicy policy : policies) {
@@ -2795,6 +2817,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void setRestrictBackgroundUL(boolean restrictBackground) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackgroundUL");
         try {
@@ -3447,11 +3470,13 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private boolean isUidForegroundOnRestrictBackgroundUL(int uid) {
         final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         return isProcStateAllowedWhileOnRestrictBackground(procState);
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private boolean isUidForegroundOnRestrictPowerUL(int uid) {
         final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         return isProcStateAllowedWhileIdleOrPowerSaveMode(procState);
@@ -3467,6 +3492,7 @@
      * {@link #updateRulesForDataUsageRestrictionsUL(int)} and
      * {@link #updateRulesForPowerRestrictionsUL(int)}
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void updateUidStateUL(int uid, int uidState) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
         try {
@@ -3493,6 +3519,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void removeUidStateUL(int uid) {
         final int index = mUidState.indexOfKey(uid);
         if (index >= 0) {
@@ -3537,6 +3564,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRulesForPowerSaveUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
         try {
@@ -3547,10 +3575,12 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRuleForRestrictPowerUL(int uid) {
         updateRulesForWhitelistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRulesForDeviceIdleUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
         try {
@@ -3561,12 +3591,14 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRuleForDeviceIdleUL(int uid) {
         updateRulesForWhitelistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
     }
 
     // NOTE: since both fw_dozable and fw_powersave uses the same map
     // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
             SparseIntArray rules) {
         if (enabled) {
@@ -3611,6 +3643,7 @@
      *        {@link #mPowerSaveWhitelistExceptIdleAppIds} for checking if the {@param uid} is
      *        whitelisted.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private boolean isWhitelistedBatterySaverUL(int uid, boolean deviceIdleMode) {
         final int appId = UserHandle.getAppId(uid);
         boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
@@ -3623,6 +3656,7 @@
 
     // NOTE: since both fw_dozable and fw_powersave uses the same map
     // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
         if (enabled) {
             final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid,
@@ -3635,6 +3669,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRulesForAppIdleUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForAppIdleUL");
         try {
@@ -3664,6 +3699,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     void updateRuleForAppIdleUL(int uid) {
         if (!isUidValidForBlacklistRules(uid)) return;
 
@@ -3687,6 +3723,7 @@
      * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
      * changed.
      */
+    @GuardedBy("mUidRulesFirstLock")
     void updateRulesForAppIdleParoleUL() {
         boolean paroled = mUsageStats.isAppIdleParoleOn();
         boolean enableChain = !paroled;
@@ -3719,6 +3756,7 @@
      * Update rules that might be changed by {@link #mRestrictBackground},
      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
      */
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
     private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
         if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
@@ -3740,6 +3778,7 @@
     }
 
     // TODO: rename / document to make it clear these are global (not app-specific) rules
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForRestrictPowerUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
         try {
@@ -3751,6 +3790,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForRestrictBackgroundUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictBackgroundUL");
         try {
@@ -3771,6 +3811,7 @@
     }
 
     // TODO: refactor / consolidate all those updateXyz methods, there are way too many of them...
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForAllAppsUL(@RestrictType int type) {
         if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL-" + type);
@@ -3822,6 +3863,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForTempWhitelistChangeUL(int appId) {
         final List<UserInfo> users = mUserManager.getUsers();
         final int numUsers = users.size();
@@ -3886,6 +3928,7 @@
     /**
      * Clears all state - internal and external - associated with an UID.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void onUidDeletedUL(int uid) {
         // First cleanup in-memory state synchronously...
         mUidRules.delete(uid);
@@ -3914,6 +3957,7 @@
      *
      * <p>This method changes both the external firewall rules and the internal state.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRestrictionRulesForUidUL(int uid) {
         // Methods below only changes the firewall rules for the power-related modes.
         updateRuleForDeviceIdleUL(uid);
@@ -4104,6 +4148,7 @@
      * <p>
      * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForPowerRestrictionsUL(int uid) {
         final int oldUidRules = mUidRules.get(uid, RULE_NONE);
 
@@ -4540,6 +4585,7 @@
      * @param uidRules new UID rules; if {@code null}, only toggles chain state.
      * @param toggle whether the chain should be enabled, disabled, or not changed.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void setUidFirewallRulesUL(int chain, @Nullable SparseIntArray uidRules,
             @ChainToggleType int toggle) {
         if (uidRules != null) {
@@ -4606,6 +4652,7 @@
     /**
      * Add or remove a uid to the firewall blacklist for all network ifaces.
      */
+    @GuardedBy("mUidRulesFirstLock")
     private void enableFirewallChainUL(int chain, boolean enable) {
         if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
                 mFirewallChainStates.get(chain) == enable) {
@@ -4717,6 +4764,7 @@
         mHandler.getLooper().getQueue().addIdleHandler(handler);
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     @VisibleForTesting
     public void updateRestrictBackgroundByLowPowerModeUL(final PowerSaveState result) {
         mRestrictBackgroundPowerState = result;
@@ -5048,6 +5096,7 @@
         }
     }
 
+    @GuardedBy("mUidRulesFirstLock")
     private boolean isRestrictedByAdminUL(int uid) {
         final Set<Integer> restrictedUids = mMeteredRestrictedUids.get(
                 UserHandle.getUserId(uid));
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index c0fbfbb..18f4bc7 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -150,6 +150,7 @@
         try {
             provider.onConnected();
         } catch (RemoteException e) {
+            Slog.e(TAG, "can't connect to service " + info, e);
             // we tried
         }
         if (mCallback != null) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index dfc61d9..432d17c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -582,16 +582,15 @@
             updatedChannel.setLockscreenVisibility(
                     NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
         }
-        if (!fromUser) {
-            updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
-        }
         if (fromUser) {
             updatedChannel.lockFields(channel.getUserLockedFields());
             lockFieldsForUpdate(channel, updatedChannel);
+        } else {
+            updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
         }
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
-        if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
+        if (onlyHasDefaultChannel(pkg, uid)) {
             // copy settings to app level so they are inherited by new channels
             // when the app migrates
             r.importance = updatedChannel.getImportance();
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 6760875..b016faf 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -36,7 +36,8 @@
 
 public class ZenLog {
     private static final String TAG = "ZenLog";
-    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+    // the ZenLog is *very* verbose, so be careful about setting this to true
+    private static final boolean DEBUG = false;
 
     private static final int SIZE = Build.IS_DEBUGGABLE ? 100 : 20;
 
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 63c0baf..8013f7a 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -59,7 +59,8 @@
         pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions);
     }
 
-    public void evaluateConfig(ZenModeConfig config, boolean processSubscriptions) {
+    public void evaluateConfig(ZenModeConfig config, ComponentName trigger,
+            boolean processSubscriptions) {
         if (config == null) return;
         if (config.manualRule != null && config.manualRule.condition != null
                 && !config.manualRule.isTrueOrUnknown()) {
@@ -67,9 +68,9 @@
             config.manualRule = null;
         }
         final ArraySet<Uri> current = new ArraySet<>();
-        evaluateRule(config.manualRule, current, processSubscriptions);
+        evaluateRule(config.manualRule, current, null, processSubscriptions);
         for (ZenRule automaticRule : config.automaticRules.values()) {
-            evaluateRule(automaticRule, current, processSubscriptions);
+            evaluateRule(automaticRule, current, trigger, processSubscriptions);
             updateSnoozing(automaticRule);
         }
 
@@ -102,7 +103,7 @@
     @Override
     public void onServiceAdded(ComponentName component) {
         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
-        mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
+        mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded");
     }
 
     @Override
@@ -110,17 +111,22 @@
         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
         ZenModeConfig config = mHelper.getConfig();
         if (config == null) return;
+        ComponentName trigger = null;
         boolean updated = updateCondition(id, condition, config.manualRule);
         for (ZenRule automaticRule : config.automaticRules.values()) {
             updated |= updateCondition(id, condition, automaticRule);
             updated |= updateSnoozing(automaticRule);
+            if (updated) {
+                trigger = automaticRule.component;
+            }
         }
         if (updated) {
-            mHelper.setConfig(config, "conditionChanged");
+            mHelper.setConfig(config, trigger, "conditionChanged");
         }
     }
 
-    private void evaluateRule(ZenRule rule, ArraySet<Uri> current, boolean processSubscriptions) {
+    private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger,
+            boolean processSubscriptions) {
         if (rule == null || rule.conditionId == null) return;
         final Uri id = rule.conditionId;
         boolean isSystemCondition = false;
@@ -146,7 +152,8 @@
         if (current != null) {
             current.add(id);
         }
-        if (processSubscriptions) {
+        if (processSubscriptions && trigger != null && trigger.equals(rule.component)) {
+            if (DEBUG) Log.d(TAG, "Subscribing to " + rule.component);
             if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
                 synchronized (mSubscriptions) {
                     mSubscriptions.put(rule.conditionId, rule.component);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1954ed4..9c5e064 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -225,7 +225,7 @@
             config.user = user;
         }
         synchronized (mConfig) {
-            setConfigLocked(config, reason);
+            setConfigLocked(config, null, reason);
         }
         cleanUpZenRules();
     }
@@ -312,7 +312,7 @@
             ZenRule rule = new ZenRule();
             populateZenRule(automaticZenRule, rule, true);
             newConfig.automaticRules.put(rule.id, rule);
-            if (setConfigLocked(newConfig, reason, true)) {
+            if (setConfigLocked(newConfig, reason, rule.component, true)) {
                 return rule.id;
             } else {
                 throw new AndroidRuntimeException("Could not create rule");
@@ -342,7 +342,7 @@
             }
             populateZenRule(automaticZenRule, rule, false);
             newConfig.automaticRules.put(ruleId, rule);
-            return setConfigLocked(newConfig, reason, true);
+            return setConfigLocked(newConfig, reason, rule.component, true);
         }
     }
 
@@ -360,7 +360,7 @@
                 throw new SecurityException(
                         "Cannot delete rules not owned by your condition provider");
             }
-            return setConfigLocked(newConfig, reason, true);
+            return setConfigLocked(newConfig, reason, null, true);
         }
     }
 
@@ -376,7 +376,7 @@
                     newConfig.automaticRules.removeAt(i);
                 }
             }
-            return setConfigLocked(newConfig, reason, true);
+            return setConfigLocked(newConfig, reason, null, true);
         }
     }
 
@@ -537,7 +537,7 @@
                 newRule.enabler = caller;
                 newConfig.manualRule = newRule;
             }
-            setConfigLocked(newConfig, reason, setRingerMode);
+            setConfigLocked(newConfig, reason, null, setRingerMode);
         }
     }
 
@@ -644,7 +644,7 @@
             }
             if (DEBUG) Log.d(TAG, reason);
             synchronized (mConfig) {
-                setConfigLocked(config, reason);
+                setConfigLocked(config, null, reason);
             }
         }
     }
@@ -673,7 +673,7 @@
         synchronized (mConfig) {
             final ZenModeConfig newConfig = mConfig.copy();
             newConfig.applyNotificationPolicy(policy);
-            setConfigLocked(newConfig, "setNotificationPolicy");
+            setConfigLocked(newConfig, null, "setNotificationPolicy");
         }
     }
 
@@ -697,7 +697,7 @@
                     }
                 }
             }
-            setConfigLocked(newConfig, "cleanUpZenRules");
+            setConfigLocked(newConfig, null, "cleanUpZenRules");
         }
     }
 
@@ -710,17 +710,19 @@
         }
     }
 
-    public boolean setConfigLocked(ZenModeConfig config, String reason) {
-        return setConfigLocked(config, reason, true /*setRingerMode*/);
+    public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
+            String reason) {
+        return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/);
     }
 
-    public void setConfig(ZenModeConfig config, String reason) {
+    public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) {
         synchronized (mConfig) {
-            setConfigLocked(config, reason);
+            setConfigLocked(config, triggeringComponent, reason);
         }
     }
 
-    private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
+    private boolean setConfigLocked(ZenModeConfig config, String reason,
+            ComponentName triggeringComponent, boolean setRingerMode) {
         final long identity = Binder.clearCallingIdentity();
         try {
             if (config == null || !config.isValid()) {
@@ -733,7 +735,8 @@
                 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
                 return true;
             }
-            mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
+            // may modify config
+            mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
             mConfigs.put(config.user, config);
             if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
             ZenLog.traceConfig(reason, mConfig, config);
@@ -746,7 +749,7 @@
                 dispatchOnPolicyChanged();
             }
             mConfig = config;
-            mHandler.postApplyConfig(config, reason, setRingerMode);
+            mHandler.postApplyConfig(config, reason, triggeringComponent, setRingerMode);
             return true;
         } catch (SecurityException e) {
             Log.wtf(TAG, "Invalid rule in config", e);
@@ -756,13 +759,14 @@
         }
     }
 
-    private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+    private void applyConfig(ZenModeConfig config, String reason,
+            ComponentName triggeringComponent, boolean setRingerMode) {
         final String val = Integer.toString(config.hashCode());
         Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
         if (!evaluateZenMode(reason, setRingerMode)) {
             applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
         }
-        mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+        mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
     }
 
     private int getZenModeSetting() {
@@ -1268,13 +1272,16 @@
 
         private final class ConfigMessageData {
             public final ZenModeConfig config;
+            public ComponentName triggeringComponent;
             public final String reason;
             public final boolean setRingerMode;
 
-            ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
+            ConfigMessageData(ZenModeConfig config, String reason,
+                    ComponentName triggeringComponent, boolean setRingerMode) {
                 this.config = config;
                 this.reason = reason;
                 this.setRingerMode = setRingerMode;
+                this.triggeringComponent = triggeringComponent;
             }
         }
 
@@ -1294,9 +1301,10 @@
             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
         }
 
-        private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+        private void postApplyConfig(ZenModeConfig config, String reason,
+                ComponentName triggeringComponent, boolean setRingerMode) {
             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
-                    new ConfigMessageData(config, reason, setRingerMode)));
+                    new ConfigMessageData(config, reason, triggeringComponent, setRingerMode)));
         }
 
         @Override
@@ -1311,7 +1319,7 @@
                 case MSG_APPLY_CONFIG:
                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
                     applyConfig(applyConfigData.config, applyConfigData.reason,
-                            applyConfigData.setRingerMode);
+                            applyConfigData.triggeringComponent, applyConfigData.setRingerMode);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b0be4a9..55b1940 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,6 +34,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.DexoptUtils;
@@ -289,7 +290,8 @@
             mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
                     compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
                     false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
-                    profileName, dexMetadataPath, getReasonName(compilationReason));
+                    profileName, dexMetadataPath,
+                    getAugmentedReasonName(compilationReason, dexMetadataPath != null));
 
             if (packageStats != null) {
                 long endTime = System.currentTimeMillis();
@@ -302,6 +304,12 @@
         }
     }
 
+    private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) {
+        String annotation = useDexMetadata
+                ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : "";
+        return getReasonName(compilationReason) + annotation;
+    }
+
     /**
      * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}.
      *
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3919f50..30224d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -452,7 +452,6 @@
     static final int SCAN_NEW_INSTALL = 1<<2;
     static final int SCAN_UPDATE_TIME = 1<<3;
     static final int SCAN_BOOTING = 1<<4;
-    static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<6;
     static final int SCAN_REQUIRE_KNOWN = 1<<7;
     static final int SCAN_MOVE = 1<<8;
     static final int SCAN_INITIAL = 1<<9;
@@ -475,7 +474,6 @@
             SCAN_NEW_INSTALL,
             SCAN_UPDATE_TIME,
             SCAN_BOOTING,
-            SCAN_DELETE_DATA_ON_FAILURES,
             SCAN_REQUIRE_KNOWN,
             SCAN_MOVE,
             SCAN_INITIAL,
@@ -8951,15 +8949,20 @@
             }
         }
 
-        final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
+        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
+        if (scanResult.success) {
+            synchronized (mPackages) {
+                commitScanResultLocked(scanResult);
+            }
+        }
 
         if (shouldHideSystemApp) {
             synchronized (mPackages) {
                 mSettings.disableSystemPackageLPw(pkg.packageName, true);
             }
         }
-        return scannedPkg;
+        return scanResult.pkgSetting.pkg;
     }
 
     private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
@@ -9985,7 +9988,7 @@
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
-    private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
+    private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
@@ -10002,16 +10005,16 @@
             scanFlags &= ~SCAN_CHECK_ONLY;
         }
 
-        final PackageParser.Package scannedPkg;
+        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+        final List<ScanResult> scanResults = new ArrayList<>(1 + childCount);
         try {
             // Scan the parent
-            scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user);
+            scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
             // Scan the children
-            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
             for (int i = 0; i < childCount; i++) {
                 PackageParser.Package childPkg = pkg.childPackages.get(i);
-                scanPackageNewLI(childPkg, parseFlags,
-                        scanFlags, currentTime, user);
+                scanResults.add(scanPackageNewLI(childPkg, parseFlags,
+                        scanFlags, currentTime, user));
             }
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -10021,11 +10024,13 @@
             return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
         }
 
-        return scannedPkg;
+        return scanResults;
     }
 
     /** The result of a package scan. */
     private static class ScanResult {
+        /** The request that initiated the scan that produced this result. */
+        public final ScanRequest request;
         /** Whether or not the package scan was successful */
         public final boolean success;
         /**
@@ -10036,9 +10041,10 @@
         /** ABI code paths that have changed in the package scan */
         @Nullable public final List<String> changedAbiCodePath;
         public ScanResult(
-                boolean success,
+                ScanRequest request, boolean success,
                 @Nullable PackageSetting pkgSetting,
                 @Nullable List<String> changedAbiCodePath) {
+            this.request = request;
             this.success = success;
             this.pkgSetting = pkgSetting;
             this.changedAbiCodePath = changedAbiCodePath;
@@ -10181,7 +10187,7 @@
     // method. Also, we need to solve the problem of potentially creating a new shared user
     // setting. That can probably be done later and patch things up after the fact.
     @GuardedBy({"mInstallLock", "mPackages"})
-    private PackageParser.Package scanPackageNewLI(@NonNull PackageParser.Package pkg,
+    private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
 
@@ -10217,28 +10223,30 @@
                                 + " packages=" + sharedUserSetting.packages);
                 }
             }
+            final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+                    pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
+                    originalPkgSetting, realPkgName, parseFlags, scanFlags,
+                    (pkg == mPlatformPackage), user);
+            return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+        }
+    }
 
-            boolean scanSucceeded = false;
-            try {
-                final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
-                        pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
-                        originalPkgSetting, realPkgName, parseFlags, scanFlags,
-                        (pkg == mPlatformPackage), user);
-                final ScanResult result = scanPackageOnlyLI(request, mFactoryTest, currentTime);
-                if (result.success) {
-                    commitScanResultsLocked(request, result);
+
+    private void commitSuccessfulScanResults(@NonNull List<ScanResult> results)
+            throws PackageManagerException {
+        synchronized(mPackages) {
+            for (ScanResult result : results) {
+                // failures should have been caught earlier, but in case it wasn't,
+                // let's double check
+                if (!result.success) {
+                    throw new PackageManagerException(
+                            "Scan failed for " + result.request.pkg.packageName);
                 }
-                scanSucceeded = true;
-            } finally {
-                  if (!scanSucceeded && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
-                      // DELETE_DATA_ON_FAILURES is only used by frozen paths
-                      destroyAppDataLIF(pkg, UserHandle.USER_ALL,
-                              StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-                      destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
-                  }
+            }
+            for (ScanResult result : results) {
+                commitScanResultLocked(result);
             }
         }
-        return pkg;
     }
 
     /**
@@ -10249,8 +10257,8 @@
      * possible and the system is not left in an inconsistent state.
      */
     @GuardedBy({"mPackages", "mInstallLock"})
-    private void commitScanResultsLocked(@NonNull ScanRequest request, @NonNull ScanResult result)
-            throws PackageManagerException {
+    private void commitScanResultLocked(@NonNull ScanResult result) throws PackageManagerException {
+        final ScanRequest request = result.request;
         final PackageParser.Package pkg = request.pkg;
         final PackageParser.Package oldPkg = request.oldPkg;
         final @ParseFlags int parseFlags = request.parseFlags;
@@ -10831,7 +10839,7 @@
             pkgSetting.volumeUuid = volumeUuid;
         }
 
-        return new ScanResult(true, pkgSetting, changedAbiCodePath);
+        return new ScanResult(request, true, pkgSetting, changedAbiCodePath);
     }
 
     /**
@@ -16384,14 +16392,18 @@
         }
 
         try {
-            PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
+            final PackageParser.Package newPackage;
+            List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags, scanFlags,
                     System.currentTimeMillis(), user);
-
+            commitSuccessfulScanResults(scanResults);
+            // TODO(b/109941548): Child packages may return >1 result with the first being the base;
+            // we need to treat child packages as an atomic install and remove this hack
+            final ScanResult basePackageScanResult = scanResults.get(0);
+            newPackage = basePackageScanResult.pkgSetting.pkg;
             updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 prepareAppDataAfterInstallLIF(newPackage);
-
             } else {
                 // Remove package from internal structures, but keep around any
                 // data that might have already existed
@@ -16399,6 +16411,9 @@
                         PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
             }
         } catch (PackageManagerException e) {
+            destroyAppDataLIF(pkg, UserHandle.USER_ALL,
+                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+            destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
             res.setError("Package couldn't be installed in " + pkg.codePath, e);
         }
 
@@ -16655,8 +16670,10 @@
                     | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
 
             try {
-                final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
+                final List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
+                commitSuccessfulScanResults(scanResults);
+                final PackageParser.Package newPackage = scanResults.get(0).pkgSetting.pkg;
                 updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
                         installReason);
 
@@ -16794,8 +16811,11 @@
 
         PackageParser.Package newPackage = null;
         try {
+            final List<ScanResult> scanResults =
+                    scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
             // Add the package to the internal data structures
-            newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
+            commitSuccessfulScanResults(scanResults);
+            newPackage = scanResults.get(0).pkgSetting.pkg;
 
             // Set the update and install times
             PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras;
@@ -16852,7 +16872,9 @@
             }
             // Add back the old system package
             try {
-                scanPackageTracedLI(deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
+                final List<ScanResult> scanResults = scanPackageTracedLI(
+                        deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
+                commitSuccessfulScanResults(scanResults);
             } catch (PackageManagerException e) {
                 Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
             }
@@ -17663,7 +17685,7 @@
                 replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
                         installerPackageName, res, args.installReason);
             } else {
-                installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
+                installNewPackageLIF(pkg, parseFlags, scanFlags,
                         args.user, installerPackageName, volumeUuid, res, args.installReason);
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d06437e..5878762 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2419,30 +2419,30 @@
 
     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final ParcelFileDescriptor fd;
-        if (STDIN_PATH.equals(inPath)) {
-            fd = new ParcelFileDescriptor(getInFileDescriptor());
-        } else if (inPath != null) {
-            fd = openFileForSystem(inPath, "r");
-            if (fd == null) {
-                return -1;
-            }
-            sizeBytes = fd.getStatSize();
-            if (sizeBytes < 0) {
-                getErrPrintWriter().println("Unable to get size of: " + inPath);
-                return -1;
-            }
-        } else {
-            fd = new ParcelFileDescriptor(getInFileDescriptor());
-        }
-        if (sizeBytes <= 0) {
-            getErrPrintWriter().println("Error: must specify a APK size");
-            return 1;
-        }
-
         PackageInstaller.Session session = null;
         try {
+            final PrintWriter pw = getOutPrintWriter();
+            final ParcelFileDescriptor fd;
+            if (STDIN_PATH.equals(inPath)) {
+                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+            } else if (inPath != null) {
+                fd = openFileForSystem(inPath, "r");
+                if (fd == null) {
+                    return -1;
+                }
+                sizeBytes = fd.getStatSize();
+                if (sizeBytes < 0) {
+                    getErrPrintWriter().println("Unable to get size of: " + inPath);
+                    return -1;
+                }
+            } else {
+                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+            }
+            if (sizeBytes <= 0) {
+                getErrPrintWriter().println("Error: must specify a APK size");
+                return 1;
+            }
+
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
             session.write(splitName, 0, sizeBytes, fd);
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 0ba7822..21daa39 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -519,6 +519,11 @@
     private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
     private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
     private static final int TRON_COMPILATION_REASON_SHARED = 8;
+    private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9;
+
+    // The annotation to add as a suffix to the compilation reason when dexopt was
+    // performed with dex metadata.
+    public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm";
 
     /**
      * Convert the compilation reason to an int suitable to be logged to TRON.
@@ -534,6 +539,10 @@
             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
             case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
             case "shared" : return TRON_COMPILATION_REASON_SHARED;
+            // This is a special marker for dex metadata installation that does not
+            // have an equivalent as a system property.
+            case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
             default: return TRON_COMPILATION_REASON_UNKNOWN;
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 8aed957..8a6fbaa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2059,6 +2059,7 @@
         }
     }
 
+    @GuardedBy({"mSettings.mLock", "mLock"})
     private int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
         int size = 0;
         for (BasePermission perm : mSettings.mPermissions.values()) {
@@ -2067,6 +2068,7 @@
         return size;
     }
 
+    @GuardedBy({"mSettings.mLock", "mLock"})
     private void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
         // We calculate the max size of permissions defined by this uid and throw
         // if that plus the size of 'info' would exceed our stated maximum.
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ded2c15..73775b4 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -219,12 +219,12 @@
     }
 
     @Override
-    public int checkSlicePermission(Uri uri, String pkg, int pid, int uid,
+    public int checkSlicePermission(Uri uri, String callingPkg, String pkg, int pid, int uid,
             String[] autoGrantPermissions) {
         int userId = UserHandle.getUserId(uid);
         if (pkg == null) {
             for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
-                if (checkSlicePermission(uri, p, pid, uid, autoGrantPermissions)
+                if (checkSlicePermission(uri, callingPkg, p, pid, uid, autoGrantPermissions)
                         == PERMISSION_GRANTED) {
                     return PERMISSION_GRANTED;
                 }
@@ -237,9 +237,9 @@
         if (mPermissions.hasPermission(pkg, userId, uri)) {
             return PackageManager.PERMISSION_GRANTED;
         }
-        if (autoGrantPermissions != null) {
+        if (autoGrantPermissions != null && callingPkg != null) {
             // Need to own the Uri to call in with permissions to grant.
-            enforceOwner(pkg, uri, userId);
+            enforceOwner(callingPkg, uri, userId);
             for (String perm : autoGrantPermissions) {
                 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
                     int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
@@ -391,7 +391,7 @@
     }
 
     protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
-        return checkSlicePermission(uri, pkg, uid, pid, null);
+        return checkSlicePermission(uri, null, pkg, uid, pid, null);
     }
 
     private String getProviderPkg(Uri uri, int user) {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index c7c24a5..2175772 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1179,6 +1179,7 @@
         }
     }
 
+    @GuardedBy("StatsCompanionService.sStatsdLock")
     private void forgetEverythingLocked() {
         sStatsd = null;
         mContext.unregisterReceiver(mAppUpdateReceiver);
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index c1c32c2..774a3bc 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -708,8 +708,10 @@
         @Override
         public void onServiceDisconnected(ComponentName name) {
             synchronized (mLock) {
-                clearClientLocked();
-                mRemoteInstance = null;
+                if (mRemoteInstance != null) {
+                    clearClientLocked();
+                    mRemoteInstance = null;
+                }
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index b392935..cde8e63 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -21,15 +21,13 @@
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
 import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertEquals;
 
 import android.media.AudioManager;
 import android.os.Looper;
 import android.os.test.TestLooper;
 import android.support.test.filters.SmallTest;
 
+import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import java.util.ArrayList;
 import org.junit.Before;
 import org.junit.Test;
@@ -139,52 +137,56 @@
         mMusicMute = true;
         mMusicMaxVolume = 20;
         int scaledVolume = VolumeControlAction.scaleToCecVolume(10, mMusicMaxVolume);
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder.buildReportAudioStatus(
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildReportAudioStatus(
             ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true);
         HdmiCecMessage messageGive = HdmiCecMessageBuilder.buildGiveAudioStatus(
             ADDR_TV, ADDR_AUDIO_SYSTEM);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
     public void handleGiveSystemAudioModeStatus_originalOff() {
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         HdmiCecMessage messageGive = HdmiCecMessageBuilder
             .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
     public void handleRequestArcInitiate() {
         // TODO(b/80296911): Add tests when finishing handler impl.
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildInitiateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);
         HdmiCecMessage message = HdmiCecMessageBuilder
             .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
     public void handleRequestArcTermination() {
         // TODO(b/80297105): Add tests when finishing handler impl.
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildTerminateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);
         HdmiCecMessage messageRequestOff = HdmiCecMessageBuilder
             .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(messageRequestOff));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(messageRequestOff))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
@@ -196,28 +198,31 @@
             .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
 
         // Check if originally off
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
 
         // Check if correctly turned on
-        expectMessage = HdmiCecMessageBuilder
+        expectedMessage = HdmiCecMessageBuilder
             .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
 
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
-        assertFalse(mMusicMute);
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
+        assertThat(mMusicMute).isEqualTo(false);
     }
 
     @Test
     public void handleSystemAudioModeRequest_turnOffByTv() {
-        assertFalse(mMusicMute);
+        assertThat(mMusicMute).isEqualTo(false);
 
         // Check if feature correctly turned off
         HdmiCecMessage messageGive = HdmiCecMessageBuilder
@@ -225,18 +230,20 @@
         HdmiCecMessage messageRequestOff = HdmiCecMessageBuilder
             .buildSystemAudioModeRequest(ADDR_TV, ADDR_AUDIO_SYSTEM, 2, false);
 
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildSetSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
 
-        expectMessage = HdmiCecMessageBuilder
+        expectedMessage = HdmiCecMessageBuilder
             .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
-        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
+                .isEqualTo(true);
         mTestLooper.dispatchAll();
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
-        assertTrue(mMusicMute);
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
+        assertThat(mMusicMute).isEqualTo(true);
     }
 
     @Test
@@ -247,10 +254,10 @@
         // Check if standby correctly turns off the feature
         mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
-        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
             .buildSetSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
-        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
-        assertTrue(mMusicMute);
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
+        assertThat(mMusicMute).isEqualTo(true);
     }
 
     @Test
@@ -296,4 +303,50 @@
         assertThat(mHdmiCecLocalDeviceAudioSystem
             .getActions(SystemAudioInitiationActionFromAvr.class)).isNotEmpty();
     }
+
+    @Test
+    public void handleActiveSource_updateActiveSource() {
+        HdmiCecMessage message = HdmiCecMessageBuilder
+            .buildActiveSource(ADDR_TV, 0x0000);
+        ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message))
+                .isEqualTo(true);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().equals(expectedActiveSource))
+                .isEqualTo(true);
+    }
+
+    @Test
+    public void terminateSystemAudioMode_systemAudioModeOff() {
+        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isEqualTo(false);
+
+        mMusicMute = false;
+        HdmiCecMessage message = HdmiCecMessageBuilder
+                .buildSetSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
+
+        mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode();
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isEqualTo(false);
+        assertThat(mMusicMute).isEqualTo(false);
+        assertThat(mNativeWrapper.getResultMessage()).isNotEqualTo(message);
+    }
+
+    @Test
+    public void terminateSystemAudioMode_systemAudioModeOn() {
+        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isEqualTo(true);
+
+        mMusicMute = false;
+        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
+                .buildSetSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
+
+        mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode();
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isEqualTo(false);
+        assertThat(mMusicMute).isEqualTo(true);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessage()).isEqualTo(expectedMessage);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 02d5869..73adf25 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -27,6 +27,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -93,11 +94,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PreferencesHelperTest extends UiServiceTestCase {
-    private static final String PKG = "com.android.server.notification";
-    private static final int UID = 0;
+    private static final int UID_N_MR1 = 0;
     private static final UserHandle USER = UserHandle.of(0);
-    private static final String UPDATED_PKG = "updatedPkg";
-    private static final int UID2 = 1111;
+    private static final int UID_O = 1111;
     private static final String SYSTEM_PKG = "android";
     private static final int SYSTEM_UID= 1000;
     private static final UserHandle USER2 = UserHandle.of(10);
@@ -130,16 +129,16 @@
         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         final ApplicationInfo upgrade = new ApplicationInfo();
         upgrade.targetSdkVersion = Build.VERSION_CODES.O;
-        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
-        when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
+        when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
+        when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(upgrade);
         when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade);
-        when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
-        when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
+        when(mPm.getPackageUidAsUser(eq(PKG_N_MR1), anyInt())).thenReturn(UID_N_MR1);
+        when(mPm.getPackageUidAsUser(eq(PKG_O), anyInt())).thenReturn(UID_O);
         when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID);
         PackageInfo info = mock(PackageInfo.class);
         info.signatures = new Signature[] {mock(Signature.class)};
         when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info);
-        when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt()))
+        when(mPm.getPackageInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt()))
                 .thenReturn(mock(PackageInfo.class));
         when(mContext.getResources()).thenReturn(
                 InstrumentationRegistry.getContext().getResources());
@@ -151,7 +150,7 @@
         TestableContentResolver contentResolver = getContext().getContentResolver();
         contentResolver.setFallbackToExisting(false);
         Secure.putIntForUser(contentResolver,
-                Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
+                Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1));
 
         ContentProvider testContentProvider = mock(ContentProvider.class);
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
@@ -270,28 +269,29 @@
         channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
         channel2.setLightColor(Color.BLUE);
 
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
 
-        mHelper.setShowBadge(PKG, UID, true);
-        mHelper.setAppImportanceLocked(PKG, UID);
+        mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
+        mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, channel1.getId(),
                 channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
-        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
+        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
 
         loadStreamXml(baos, false);
 
-        assertTrue(mHelper.canShowBadge(PKG, UID));
-        assertTrue(mHelper.getIsAppImportanceLocked(PKG, UID));
-        assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
+        assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
+        assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         compareChannels(channel2,
-                mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
         List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -332,36 +332,36 @@
         NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
         channel3.enableVibration(true);
 
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, false, false);
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
+        mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
 
-        mHelper.setShowBadge(PKG, UID, true);
+        mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
 
-        mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE);
+        mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
                 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
-        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG},
-                new int[]{UID, UID2});
+        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1, PKG_O},
+                new int[]{UID_N_MR1, UID_O});
 
-        mHelper.setShowBadge(UPDATED_PKG, UID2, true);
+        mHelper.setShowBadge(PKG_O, UID_O, true);
 
         loadStreamXml(baos, true);
 
-        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2));
-        assertTrue(mHelper.canShowBadge(PKG, UID));
-        assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
+        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
+        assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         compareChannels(channel2,
-                mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
         compareChannels(channel3,
-                mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
 
         List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -388,9 +388,9 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
 
         // Testing that in restore we are given the canonical version
         loadStreamXml(baos, true);
@@ -414,13 +414,13 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
 
         loadStreamXml(baos, true);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
-                PKG, UID, channel.getId(), false);
+                PKG_N_MR1, UID_N_MR1, channel.getId(), false);
         assertEquals(localUri, actualChannel.getSound());
     }
 
@@ -435,13 +435,13 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
 
         loadStreamXml(baos, true);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
-                PKG, UID, channel.getId(), false);
+                PKG_N_MR1, UID_N_MR1, channel.getId(), false);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
     }
 
@@ -456,7 +456,7 @@
         when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))).thenReturn(null);
         String id = "id";
         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
-                + "<package name=\"com.android.server.notification\" show_badge=\"true\">\n"
+                + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
                 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
                 + "sound=\"" + SOUND_URI + "\" "
                 + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n"
@@ -467,7 +467,7 @@
 
         loadByteArrayXml(backupWithUncanonicalizedSoundUri.getBytes(), true);
 
-        NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG, UID, id, false);
+        NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
     }
 
@@ -476,13 +476,13 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(null, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
 
         loadStreamXml(baos, true);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
-                PKG, UID, channel.getId(), false);
+                PKG_N_MR1, UID_N_MR1, channel.getId(), false);
         assertEquals(null, actualChannel.getSound());
     }
 
@@ -498,19 +498,20 @@
                 new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
         channel3.setGroup(ncg.getId());
 
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
 
-        mHelper.deleteNotificationChannel(PKG, UID, channel1.getId());
-        mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId());
-        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId());
+        mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId());
+        assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
                 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
-        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
+        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
 
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
@@ -518,21 +519,21 @@
         parser.nextTag();
         mHelper.readXml(parser, true);
 
-        assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
-        assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
-        assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
-        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
-        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
+        assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
+        assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
+        assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1));
+        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG_N_MR1, UID_N_MR1));
+        assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
     }
 
     @Test
     public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
         loadStreamXml(baos, false);
 
-        final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID,
+        final NotificationChannel updated = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
         assertFalse(updated.canBypassDnd());
@@ -542,28 +543,29 @@
 
     @Test
     public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
-        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
+        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
+                UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
         loadStreamXml(baos, false);
 
         assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
-                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
+                PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
     }
 
     @Test
     public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
         final String preupgradeXml = "<ranking version=\"1\">\n"
-                + "<package name=\"" + PKG
+                + "<package name=\"" + PKG_N_MR1
                 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
                 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
-                + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID + "\" />\n"
-                + "<package name=\"" + UPDATED_PKG + "\" uid=\"" + UID2 + "\" visibility=\""
+                + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID_N_MR1 + "\" />\n"
+                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
                 + Notification.VISIBILITY_PRIVATE + "\" />\n"
                 + "</ranking>";
         XmlPullParser parser = Xml.newPullParser();
@@ -573,7 +575,7 @@
         mHelper.readXml(parser, false);
 
         final NotificationChannel updated1 =
-            mHelper.getNotificationChannel(PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
+            mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
         assertTrue(updated1.canBypassDnd());
         assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
@@ -583,71 +585,71 @@
                 updated1.getUserLockedFields());
 
         // No Default Channel created for updated packages
-        assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
+        assertEquals(null, mHelper.getNotificationChannel(PKG_O, UID_O,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
     public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception {
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
-                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
+                PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertTrue(defaultChannel != null);
         ByteArrayOutputStream baos =
-                writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID);
+                writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, NotificationChannel.DEFAULT_CHANNEL_ID);
         // Load package at higher sdk.
         final ApplicationInfo upgraded = new ApplicationInfo();
         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
+        when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
         loadStreamXml(baos, false);
 
         // Default Channel should be gone.
-        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
+        assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
     public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID,
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
 
         // Load package at higher sdk.
         final ApplicationInfo upgraded = new ApplicationInfo();
         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
+        when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
         loadStreamXml(baos, false);
 
         // Default Channel should be gone.
-        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
+        assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
     public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
-        mHelper.createNotificationChannel(PKG, UID,
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
 
         loadStreamXml(baos, false);
 
         // Should still have the newly created channel that wasn't in the xml.
-        assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
+        assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "bananas", false) != null);
     }
 
     @Test
     public void testCreateChannel_blocked() throws Exception {
-        mHelper.setImportance(PKG, UID, IMPORTANCE_NONE);
+        mHelper.setImportance(PKG_N_MR1, UID_N_MR1, IMPORTANCE_NONE);
 
-        mHelper.createNotificationChannel(PKG, UID,
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
     }
 
     @Test
     public void testCreateChannel_badImportance() throws Exception {
         try {
-            mHelper.createNotificationChannel(PKG, UID,
+            mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                     new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1),
                     true, false);
             fail("Was allowed to create a channel with invalid importance");
@@ -655,7 +657,7 @@
             // yay
         }
         try {
-            mHelper.createNotificationChannel(PKG, UID,
+            mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                     new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED),
                     true, false);
             fail("Was allowed to create a channel with invalid importance");
@@ -663,16 +665,16 @@
             // yay
         }
         try {
-            mHelper.createNotificationChannel(PKG, UID,
+            mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                     new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1),
                     true, false);
             fail("Was allowed to create a channel with invalid importance");
         } catch (IllegalArgumentException e) {
             // yay
         }
-        mHelper.createNotificationChannel(PKG, UID,
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false);
-        mHelper.createNotificationChannel(PKG, UID,
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false);
     }
 
@@ -687,7 +689,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, false, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false);
 
         // same id, try to update all fields
         final NotificationChannel channel2 =
@@ -697,70 +699,109 @@
         channel2.setBypassDnd(false);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
 
-        mHelper.updateNotificationChannel(PKG, UID, channel2, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true);
 
         // all fields should be changed
-        assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
+        assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false));
 
         verify(mHandler, times(1)).requestSort();
     }
 
     @Test
     public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
-        mHelper.setImportance(PKG, UID, IMPORTANCE_UNSPECIFIED);
-        assertTrue(mHelper.canShowBadge(PKG, UID));
-        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
+        mHelper.setImportance(PKG_N_MR1, UID_N_MR1, IMPORTANCE_UNSPECIFIED);
+        assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
-                mHelper.getPackageVisibility(PKG, UID));
-        assertFalse(mHelper.getIsAppImportanceLocked(PKG, UID));
+                mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
+        assertFalse(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
 
         NotificationChannel defaultChannel = mHelper.getNotificationChannel(
-                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
+                PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
 
         defaultChannel.setShowBadge(false);
         defaultChannel.setImportance(IMPORTANCE_NONE);
         defaultChannel.setBypassDnd(true);
         defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.setAppImportanceLocked(PKG, UID);
-        mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
+        mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
 
         // ensure app level fields are changed
-        assertFalse(mHelper.canShowBadge(PKG, UID));
-        assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG, UID));
-        assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG, UID));
-        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG, UID));
-        assertTrue(mHelper.getIsAppImportanceLocked(PKG, UID));
+        assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
+        assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
+                UID_N_MR1));
+        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_N_MR1, UID_N_MR1));
+        assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
     }
 
     @Test
     public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, false, false);
-        assertTrue(mHelper.canShowBadge(PKG, UID));
-        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
+        mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
+        assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
+        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
-                mHelper.getPackageVisibility(PKG, UID));
+                mHelper.getPackageVisibility(PKG_O, UID_O));
 
         channel.setShowBadge(false);
         channel.setImportance(IMPORTANCE_NONE);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.updateNotificationChannel(PKG, UID, channel, true);
+        mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true);
 
         // ensure app level fields are not changed
-        assertTrue(mHelper.canShowBadge(PKG, UID));
-        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
+        assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
+        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
-                mHelper.getPackageVisibility(PKG, UID));
-        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
+                mHelper.getPackageVisibility(PKG_O, UID_O));
+        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O,
+                UID_O));
+        assertFalse(mHelper.getIsAppImportanceLocked(PKG_O, UID_O));
+    }
+
+    @Test
+    public void testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels() throws Exception {
+        final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false);
+        assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
+        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+                mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
+
+        channel.setShowBadge(false);
+        channel.setImportance(IMPORTANCE_NONE);
+        channel.setBypassDnd(true);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
+
+        NotificationChannel defaultChannel = mHelper.getNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
+
+        defaultChannel.setShowBadge(false);
+        defaultChannel.setImportance(IMPORTANCE_NONE);
+        defaultChannel.setBypassDnd(true);
+        defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
+
+        // ensure app level fields are not changed
+        assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
+        assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+                mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
+        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
+                UID_N_MR1));
     }
 
     @Test
     public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception {
-        assertEquals(null, mHelper.getNotificationChannel(PKG, UID, "garbage", false));
+        assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "garbage", false));
     }
 
     @Test
@@ -778,10 +819,10 @@
         }
         channel.lockFields(lockMask);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
 
         NotificationChannel savedChannel =
-                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
 
         assertEquals(channel.getName(), savedChannel.getName());
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
@@ -807,10 +848,10 @@
         }
         channel.lockFields(lockMask);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
 
         NotificationChannel savedChannel =
-                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
 
         assertEquals(channel.getName(), savedChannel.getName());
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
@@ -833,103 +874,103 @@
 
     @Test
     public void testLockFields_soundAndVibration() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setSound(new Uri.Builder().scheme("test").build(),
                 new AudioAttributes.Builder().build());
         update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
-        mHelper.updateNotificationChannel(PKG, UID, update1, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                 | NotificationChannel.USER_LOCKED_SOUND,
-                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
                         .getUserLockedFields());
 
         NotificationChannel update2 = getChannel();
         update2.enableVibration(true);
-        mHelper.updateNotificationChannel(PKG, UID, update2, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                         | NotificationChannel.USER_LOCKED_SOUND
                         | NotificationChannel.USER_LOCKED_VIBRATION,
-                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
                         .getUserLockedFields());
     }
 
     @Test
     public void testLockFields_vibrationAndLights() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setVibrationPattern(new long[]{7945, 46 ,246});
-        mHelper.updateNotificationChannel(PKG, UID, update1, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
-                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.enableLights(true);
-        mHelper.updateNotificationChannel(PKG, UID, update2, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
                         | NotificationChannel.USER_LOCKED_LIGHTS,
-                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
                         .getUserLockedFields());
     }
 
     @Test
     public void testLockFields_lightsAndImportance() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setLightColor(Color.GREEN);
-        mHelper.updateNotificationChannel(PKG, UID, update1, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
-                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.setImportance(IMPORTANCE_DEFAULT);
-        mHelper.updateNotificationChannel(PKG, UID, update2, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
                         | NotificationChannel.USER_LOCKED_IMPORTANCE,
-                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
                         .getUserLockedFields());
     }
 
     @Test
     public void testLockFields_visibilityAndDndAndBadge() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
         assertEquals(0,
-                mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update1 = getChannel();
         update1.setBypassDnd(true);
-        mHelper.updateNotificationChannel(PKG, UID, update1, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
-                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
-        mHelper.updateNotificationChannel(PKG, UID, update2, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                         | NotificationChannel.USER_LOCKED_VISIBILITY,
-                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update3 = getChannel();
         update3.setShowBadge(false);
-        mHelper.updateNotificationChannel(PKG, UID, update3, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                         | NotificationChannel.USER_LOCKED_VISIBILITY
                         | NotificationChannel.USER_LOCKED_SHOW_BADGE,
-                mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update3.getId(), false)
                         .getUserLockedFields());
     }
 
     @Test
     public void testDeleteNonExistentChannel() throws Exception {
-        mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
+        mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist");
     }
 
     @Test
@@ -942,16 +983,16 @@
         channel.enableVibration(true);
         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
 
         // Does not return deleted channel
         NotificationChannel response =
-                mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false);
         assertNull(response);
 
         // Returns deleted channel
-        response = mHelper.getNotificationChannel(PKG, UID, channel.getId(), true);
+        response = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true);
         compareChannels(channel, response);
         assertTrue(response.isDeleted());
     }
@@ -971,14 +1012,14 @@
         NotificationChannel channel2 =
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
         channelMap.put(channel2.getId(), channel2);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
 
-        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
 
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
-                mHelper.getNotificationChannels(PKG, UID, false).getList();
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList();
         assertEquals(2, channels.size());   // Default channel + non-deleted channel
         for (NotificationChannel nc : channels) {
             if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
@@ -987,7 +1028,7 @@
         }
 
         // Returns deleted channels too
-        channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
+        channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList();
         assertEquals(3, channels.size());               // Includes default channel
         for (NotificationChannel nc : channels) {
             if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
@@ -1004,15 +1045,15 @@
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel3 =
                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
 
-        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
-        mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId());
 
-        assertEquals(2, mHelper.getDeletedChannelCount(PKG, UID));
-        assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID2));
+        assertEquals(2, mHelper.getDeletedChannelCount(PKG_N_MR1, UID_N_MR1));
+        assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID_O));
     }
 
     @Test
@@ -1023,14 +1064,14 @@
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE);
         NotificationChannel channel3 =
                 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
 
-        mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId());
 
-        assertEquals(1, mHelper.getBlockedChannelCount(PKG, UID));
-        assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID2));
+        assertEquals(1, mHelper.getBlockedChannelCount(PKG_N_MR1, UID_N_MR1));
+        assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID_O));
     }
 
     @Test
@@ -1039,7 +1080,7 @@
         // expected result: areChannelsBypassingDnd = false
         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1048,18 +1089,18 @@
         // expected result: areChannelsBypassingDnd = true
         NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel2.setBypassDnd(true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, true);
         assertTrue(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
         resetZenModeHelper();
 
         // delete channels
-        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
         assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
         resetZenModeHelper();
 
-        mHelper.deleteNotificationChannel(PKG, UID, channel2.getId());
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId());
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1071,7 +1112,7 @@
         // expected result: areChannelsBypassingDnd = false
         // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
         NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1079,7 +1120,7 @@
         // update channel so it CAN bypass dnd:
         // expected result: areChannelsBypassingDnd = true
         channel.setBypassDnd(true);
-        mHelper.updateNotificationChannel(PKG, UID, channel, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
         assertTrue(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1087,7 +1128,7 @@
         // update channel so it can't bypass dnd:
         // expected result: areChannelsBypassingDnd = false
         channel.setBypassDnd(false);
-        mHelper.updateNotificationChannel(PKG, UID, channel, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1124,33 +1165,33 @@
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
-        mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
 
         NotificationChannel newChannel = new NotificationChannel(
                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
         newChannel.setVibrationPattern(new long[]{100});
 
-        mHelper.createNotificationChannel(PKG, UID, newChannel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false);
 
         // No long deleted, using old settings
         compareChannels(channel,
-                mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
     }
 
     @Test
     public void testOnlyHasDefaultChannel() throws Exception {
-        assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID));
-        assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2));
+        assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
+        assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O));
 
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
-        assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID));
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
+        assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1));
     }
 
     @Test
     public void testCreateChannel_defaultChannelId() throws Exception {
         try {
-            mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
+            mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel(
                     NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false);
             fail("Allowed to create default channel");
         } catch (IllegalArgumentException e) {
@@ -1165,17 +1206,17 @@
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
 
         NotificationChannel newChannel = new NotificationChannel(
                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
         newChannel.setVibrationPattern(new long[]{100});
 
-        mHelper.createNotificationChannel(PKG, UID, newChannel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false);
 
         // Old settings not overridden
         compareChannels(channel,
-                mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
     }
 
     @Test
@@ -1184,9 +1225,9 @@
         final NotificationChannel channel = new NotificationChannel("id2", "name2",
                  NotificationManager.IMPORTANCE_DEFAULT);
         channel.setSound(sound, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
         assertEquals(sound, mHelper.getNotificationChannel(
-                PKG, UID, channel.getId(), false).getSound());
+                PKG_N_MR1, UID_N_MR1, channel.getId(), false).getSound());
     }
 
     @Test
@@ -1196,13 +1237,13 @@
         NotificationChannel channel2 =
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
 
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false);
 
-        mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
+        mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1);
 
         // Only default channel remains
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size());
     }
 
     @Test
@@ -1218,28 +1259,28 @@
                 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
         groupedAndDeleted.setGroup("totally");
 
-        mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true);
-        mHelper.createNotificationChannelGroup(PKG, UID, deleted, true);
-        mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true, false);
-        mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true, false);
-        mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true, false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false);
 
-        mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId());
+        mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId());
 
-        assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG, UID));
-        assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG, UID));
+        assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1));
+        assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
 
-        assertNull(mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), false));
+        assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
         compareChannels(groupedAndDeleted,
-                mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), true));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
 
         compareChannels(groupedButNotDeleted,
-                mHelper.getNotificationChannel(PKG, UID, groupedButNotDeleted.getId(), false));
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
         compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
-                PKG, UID, nonGroupedNonDeletedChannel.getId(), false));
+                PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false));
 
         // notDeleted
-        assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size());
+        assertEquals(1, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).size());
 
         verify(mHandler, never()).requestSort();
     }
@@ -1253,11 +1294,11 @@
 
             final ApplicationInfo legacy = new ApplicationInfo();
             legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
-            when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
+            when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
 
             // create records with the default channel for all user 0 and user 1 uids
-            mHelper.getImportance(PKG, user0Uids[i]);
-            mHelper.getImportance(PKG, user1Uids[i]);
+            mHelper.getImportance(PKG_N_MR1, user0Uids[i]);
+            mHelper.getImportance(PKG_N_MR1, user1Uids[i]);
         }
 
         mHelper.onUserRemoved(1);
@@ -1265,12 +1306,12 @@
         // user 0 records remain
         for (int i = 0; i < user0Uids.length; i++) {
             assertEquals(1,
-                    mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size());
+                    mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false).getList().size());
         }
         // user 1 records are gone
         for (int i = 0; i < user1Uids.length; i++) {
             assertEquals(0,
-                    mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size());
+                    mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false).getList().size());
         }
     }
 
@@ -1279,71 +1320,77 @@
         // Deleted
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
 
-        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
+        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
 
-        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size());
 
         // Not deleted
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
 
-        mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
-        assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+        mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
+        assertEquals(2, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
     }
 
     @Test
     public void testOnPackageChanged_packageRemoval_importance() throws Exception {
-        mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_HIGH);
+        mHelper.setImportance(PKG_N_MR1, UID_N_MR1, NotificationManager.IMPORTANCE_HIGH);
 
-        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
+        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
 
-        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
+        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
+                UID_N_MR1));
     }
 
     @Test
     public void testOnPackageChanged_packageRemoval_groups() throws Exception {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
 
-        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
+        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
+                UID_N_MR1});
 
         assertEquals(0,
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList().size());
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList().size());
     }
 
     @Test
     public void testOnPackageChange_downgradeTargetSdk() throws Exception {
         // create channel as api 26
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false);
+        mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
 
         // install new app version targeting 25
         final ApplicationInfo legacy = new ApplicationInfo();
         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
-        when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(legacy);
+        when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(legacy);
         mHelper.onPackagesChanged(
-                false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+                false, UserHandle.USER_SYSTEM, new String[]{PKG_O}, new int[]{UID_O});
 
         // make sure the default channel was readded
-        //assertEquals(2, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
+        //assertEquals(2, mHelper.getNotificationChannels(PKG_O, UID_O, false).getList().size());
         assertNotNull(mHelper.getNotificationChannel(
-                UPDATED_PKG, UID2, NotificationChannel.DEFAULT_CHANNEL_ID, false));
+                PKG_O, UID_O, NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
     public void testRecordDefaults() throws Exception {
-        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
-        assertEquals(true, mHelper.canShowBadge(PKG, UID));
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+        assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
+                UID_N_MR1));
+        assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
+        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
     }
 
     @Test
     public void testCreateGroup() throws Exception {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
-        assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next());
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
         verify(mHandler, never()).requestSort();
     }
 
@@ -1353,7 +1400,7 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup("garbage");
         try {
-            mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+            mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
             fail("Created a channel with a bad group");
         } catch (IllegalArgumentException e) {
         }
@@ -1362,45 +1409,45 @@
     @Test
     public void testCannotCreateChannel_goodGroup() throws Exception {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
 
         assertEquals(ncg.getId(),
-                mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup());
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
     }
 
     @Test
     public void testGetChannelGroups() throws Exception {
         NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
-        mHelper.createNotificationChannelGroup(PKG, UID, unused, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true);
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
         NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
 
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
         NotificationChannel channel1a =
                 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1a.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false);
 
         NotificationChannel channel2 =
                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel2.setGroup(ncg2.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false);
 
         NotificationChannel channel3 =
                 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
 
         List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
@@ -1426,19 +1473,19 @@
     @Test
     public void testGetChannelGroups_noSideEffects() throws Exception {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
 
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+        mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
 
         channel1.setImportance(IMPORTANCE_LOW);
-        mHelper.updateNotificationChannel(PKG, UID, channel1, true);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true);
 
         List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
 
         assertEquals(2, actual.size());
         for (NotificationChannelGroup group : actual) {
@@ -1451,14 +1498,14 @@
     @Test
     public void testCreateChannel_updateName() throws Exception {
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
-        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
-        NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
+        NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertEquals("hello", actual.getName());
 
         nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
 
-        actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+        actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertEquals("goodbye", actual.getName());
         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
 
@@ -1468,17 +1515,17 @@
     @Test
     public void testCreateChannel_addToGroup() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
-        mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
-        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
-        NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
+        NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertNull(actual.getGroup());
 
         nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
         nc.setGroup(group.getId());
-        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
 
-        actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+        actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertNotNull(actual.getGroup());
         assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
 
@@ -1500,7 +1547,7 @@
             String pkgName = "pkg" + i;
             int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
             for (int j = 0; j < numChannels; j++) {
-                mHelper.createNotificationChannel(pkgName, UID,
+                mHelper.createNotificationChannel(pkgName, UID_N_MR1,
                         new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false);
             }
             expectedChannels.put(pkgName, numChannels);
@@ -1508,7 +1555,7 @@
 
         // delete the first channel of the first package
         String pkg = expectedChannels.keyAt(0);
-        mHelper.deleteNotificationChannel("pkg" + 0, UID, "0");
+        mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0");
         // dump should not include deleted channels
         int count = expectedChannels.get(pkg);
         expectedChannels.put(pkg, count - 1);
@@ -1566,7 +1613,8 @@
     @Test
     public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
         String newLabel = "bananas!";
-        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
+        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
+                UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertFalse(newLabel.equals(defaultChannel.getName()));
 
@@ -1577,56 +1625,56 @@
 
         mHelper.onLocaleChanged(mContext, USER.getIdentifier());
 
-        assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
+        assertEquals(newLabel, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
     }
 
     @Test
     public void testIsGroupBlocked_noGroup() throws Exception {
-        assertFalse(mHelper.isGroupBlocked(PKG, UID, null));
+        assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, null));
 
-        assertFalse(mHelper.isGroupBlocked(PKG, UID, "non existent group"));
+        assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, "non existent group"));
     }
 
     @Test
     public void testIsGroupBlocked_notBlocked() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
-        mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
 
-        assertFalse(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+        assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
     }
 
     @Test
     public void testIsGroupBlocked_blocked() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
-        mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
         group.setBlocked(true);
-        mHelper.createNotificationChannelGroup(PKG, UID, group, false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false);
 
-        assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+        assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
     }
 
     @Test
     public void testIsGroup_appCannotResetBlock() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
-        mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
         NotificationChannelGroup group2 = group.clone();
         group2.setBlocked(true);
-        mHelper.createNotificationChannelGroup(PKG, UID, group2, false);
-        assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false);
+        assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
 
         NotificationChannelGroup group3 = group.clone();
         group3.setBlocked(false);
-        mHelper.createNotificationChannelGroup(PKG, UID, group3, true);
-        assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true);
+        assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
     }
 
     @Test
     public void testGetNotificationChannelGroupWithChannels() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
         NotificationChannelGroup other = new NotificationChannelGroup("something else", "");
-        mHelper.createNotificationChannelGroup(PKG, UID, group, true);
-        mHelper.createNotificationChannelGroup(PKG, UID, other, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true);
 
         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
         a.setGroup(group.getId());
@@ -1636,20 +1684,20 @@
         c.setGroup(group.getId());
         NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
 
-        mHelper.createNotificationChannel(PKG, UID, a, true, false);
-        mHelper.createNotificationChannel(PKG, UID, b, true, false);
-        mHelper.createNotificationChannel(PKG, UID, c, true, false);
-        mHelper.createNotificationChannel(PKG, UID, d, true, false);
-        mHelper.deleteNotificationChannel(PKG, UID, c.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false);
+        mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId());
 
         NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels(
-                PKG, UID, group.getId(), true);
+                PKG_N_MR1, UID_N_MR1, group.getId(), true);
         assertEquals(2, retrieved.getChannels().size());
         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
         compareChannels(c, findChannel(retrieved.getChannels(), c.getId()));
 
         retrieved = mHelper.getNotificationChannelGroupWithChannels(
-                PKG, UID, group.getId(), false);
+                PKG_N_MR1, UID_N_MR1, group.getId(), false);
         assertEquals(1, retrieved.getChannels().size());
         compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
     }
@@ -1670,9 +1718,9 @@
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         test.setBypassDnd(true);
 
-        mHelper.createNotificationChannel(PKG, UID, test, true, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true);
 
-        assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd());
+        assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
     }
 
     @Test
@@ -1680,9 +1728,9 @@
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         test.setBypassDnd(true);
 
-        mHelper.createNotificationChannel(PKG, 1000, test, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false);
 
-        assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
     }
 
     @Test
@@ -1701,23 +1749,23 @@
     @Test
     public void testDndPkgCanBypassDnd_update() throws Exception {
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(PKG, UID, test, true, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true);
 
         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         update.setBypassDnd(true);
-        mHelper.createNotificationChannel(PKG, UID, update, true, true);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true);
 
-        assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd());
+        assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd());
     }
 
     @Test
     public void testNormalPkgCannotBypassDnd_update() {
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(PKG, 1000, test, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false);
         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         update.setBypassDnd(true);
-        mHelper.createNotificationChannel(PKG, 1000, update, true, false);
-        assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
+        mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false);
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd());
     }
 
     @Test
@@ -1727,16 +1775,16 @@
 
     @Test
     public void testGetBlockedAppCount_noAppsForUserId() {
-        mHelper.setEnabled(PKG, 100, false);
+        mHelper.setEnabled(PKG_N_MR1, 100, false);
         assertEquals(0, mHelper.getBlockedAppCount(9));
     }
 
     @Test
     public void testGetBlockedAppCount_appsForUserId() {
-        mHelper.setEnabled(PKG, 1020, false);
-        mHelper.setEnabled(PKG, 1030, false);
-        mHelper.setEnabled(PKG, 1060, false);
-        mHelper.setEnabled(PKG, 1000, true);
+        mHelper.setEnabled(PKG_N_MR1, 1020, false);
+        mHelper.setEnabled(PKG_N_MR1, 1030, false);
+        mHelper.setEnabled(PKG_N_MR1, 1060, false);
+        mHelper.setEnabled(PKG_N_MR1, 1000, true);
         assertEquals(3, mHelper.getBlockedAppCount(0));
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 2ecda48..2a22600 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -116,7 +116,7 @@
         mZenModeHelperSpy.writeXml(serializer, forBackup, version);
         serializer.endDocument();
         serializer.flush();
-        mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
+        mZenModeHelperSpy.setConfig(new ZenModeConfig(), null, "writing xml");
         return baos;
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index 1db8967..6d4f5f8 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -120,7 +120,8 @@
                 .thenReturn(PERMISSION_DENIED);
         when(mContextSpy.checkPermission("perm2", Process.myPid(), Process.myUid()))
                 .thenReturn(PERMISSION_GRANTED);
-        mService.checkSlicePermission(TEST_URI, mContext.getPackageName(), Process.myPid(),
+        mService.checkSlicePermission(TEST_URI, mContext.getPackageName(),
+                mContext.getPackageName(), Process.myPid(),
                 Process.myUid(), testPerms);
 
         verify(mContextSpy).checkPermission(eq("perm1"), eq(Process.myPid()), eq(Process.myUid()));
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
new file mode 100644
index 0000000..9c874bf
--- /dev/null
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecom.ICallRedirectionService;
+import com.android.internal.telecom.ICallRedirectionAdapter;
+
+/**
+ * This service can be implemented to interact between Telecom and its implementor
+ * for making outgoing call with optional redirection/cancellation purposes.
+ *
+ * <p>
+ * Below is an example manifest registration for a {@code CallRedirectionService}.
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourCallRedirectionServiceImplementation"
+ *          android:permission="android.permission.BIND_REDIRECTION_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.CallRedirectionService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public abstract class CallRedirectionService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
+
+    /**
+     * An adapter to inform Telecom the response from the implementor of the Call
+     * Redirection service
+     */
+    private ICallRedirectionAdapter mCallRedirectionAdapter;
+
+    /**
+     * Telecom calls this method to inform the implemented {@link CallRedirectionService} of
+     * a new outgoing call which is being placed.
+     * @param handle the phone number dialed by the user
+     * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+     */
+    public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+
+    /**
+     * The implemented {@link CallRedirectionService} calls this method to response a request
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
+     * are required to the outgoing call, and that the call should be placed as-is.
+     */
+    public final void placeCallUnmodified() {
+        try {
+            mCallRedirectionAdapter.placeCallUnmodified();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * The implemented {@link CallRedirectionService} calls this method to response a request
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
+     * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+     * @param handle the new phone number to dial
+     * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
+     *                           If {@code null}, no change will be made to the
+     *                           {@link PhoneAccountHandle} used to place the call.
+     */
+    public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+        try {
+            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * The implemented {@link CallRedirectionService} calls this method to response a request
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
+     * call should be canceled entirely.
+     */
+    public final void cancelCall() {
+        try {
+            mCallRedirectionAdapter.cancelCall();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * A handler message to process the attempt to place call with redirection service from Telecom
+     */
+    private static final int MSG_PLACE_CALL = 1;
+
+    /**
+     * A handler to process the attempt to place call with redirection service from Telecom
+     */
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PLACE_CALL:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
+                        onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+            }
+        }
+    };
+
+    private final class CallRedirectionBinder extends ICallRedirectionService.Stub {
+
+        /**
+         * Telecom calls this method to inform the CallRedirectionService of a new outgoing call
+         * which is about to be placed.
+         * @param handle the phone number dialed by the user
+         * @param targetPhoneAccount the URI of the number the user dialed
+         */
+        @Override
+        public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
+                              PhoneAccountHandle targetPhoneAccount) {
+            Log.v(this, "placeCall");
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = adapter;
+            args.arg2 = handle;
+            args.arg3 = targetPhoneAccount;
+            mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.v(this, "onBind");
+        return new CallRedirectionBinder();
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.v(this, "onUnbind");
+        return false;
+    }
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
new file mode 100644
index 0000000..46bf983
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.net.Uri;
+import android.telecom.PhoneAccountHandle;
+
+/**
+ * Internal remote callback interface for call redirection services.
+ *
+ * @see android.telecom.CallRedirectionService
+ *
+ * {@hide}
+ */
+oneway interface ICallRedirectionAdapter {
+    void cancelCall();
+
+    void placeCallUnmodified();
+
+    void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
new file mode 100644
index 0000000..d8d360b
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.net.Uri;
+import android.telecom.PhoneAccountHandle;
+
+import com.android.internal.telecom.ICallRedirectionAdapter;
+
+/**
+ * Internal remote interface for a call redirection service.
+ *
+ * @see android.telecom.CallRedirectionService
+ *
+ * @hide
+ */
+oneway interface ICallRedirectionService {
+    void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
+            in PhoneAccountHandle targetPhoneAccount);
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cabf444..2a68044 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2012,6 +2012,15 @@
     public static final String KEY_UNDELIVERED_SMS_MESSAGE_EXPIRATION_TIME =
             "undelivered_sms_message_expiration_time";
 
+    /**
+     * Specifies a carrier-defined {@link CallRedirectionService} which Telecom will bind
+     * to for outgoing calls.  An empty string indicates that no carrier-defined
+     * {@link CallRedirectionService} is specified.
+     * @hide
+     */
+    public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
+            "call_redirection_service_component_name_string";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 3aab3fc..bffeb17 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -124,6 +125,14 @@
         mTimeStamp = timeStamp;
     }
 
+    /** @hide */
+    @NonNull
+    public abstract CellIdentity getCellIdentity();
+
+    /** @hide */
+    @NonNull
+    public abstract CellSignalStrength getCellSignalStrength();
+
     /**
      * Gets the connection status of this cell.
      *
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 6403bc5..8b8d1bb 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -45,6 +45,7 @@
         this.mCellSignalStrengthCdma = ci.mCellSignalStrengthCdma.copy();
     }
 
+    @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
     }
@@ -53,6 +54,7 @@
         mCellIdentityCdma = cid;
     }
 
+    @Override
     public CellSignalStrengthCdma getCellSignalStrength() {
         return mCellSignalStrengthCdma;
     }
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index a3a9b31..f7af1b2 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -45,6 +45,7 @@
         this.mCellSignalStrengthGsm = ci.mCellSignalStrengthGsm.copy();
     }
 
+    @Override
     public CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
     }
@@ -53,6 +54,7 @@
         mCellIdentityGsm = cid;
     }
 
+    @Override
     public CellSignalStrengthGsm getCellSignalStrength() {
         return mCellSignalStrengthGsm;
     }
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index b892e89..97d856e 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -45,6 +45,7 @@
         this.mCellSignalStrengthLte = ci.mCellSignalStrengthLte.copy();
     }
 
+    @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
         return mCellIdentityLte;
@@ -55,6 +56,7 @@
         mCellIdentityLte = cid;
     }
 
+    @Override
     public CellSignalStrengthLte getCellSignalStrength() {
         if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte);
         return mCellSignalStrengthLte;
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 7084c51..4fb1bce 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -48,6 +48,7 @@
         this.mCellSignalStrengthTdscdma = ci.mCellSignalStrengthTdscdma.copy();
     }
 
+    @Override
     public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
@@ -56,6 +57,7 @@
         mCellIdentityTdscdma = cid;
     }
 
+    @Override
     public CellSignalStrengthTdscdma getCellSignalStrength() {
         return mCellSignalStrengthTdscdma;
     }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 005f3d3..4f9dcb1 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -47,6 +47,7 @@
         this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
     }
 
+    @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
     }
@@ -55,6 +56,7 @@
         mCellIdentityWcdma = cid;
     }
 
+    @Override
     public CellSignalStrengthWcdma getCellSignalStrength() {
         return mCellSignalStrengthWcdma;
     }
diff --git a/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
similarity index 70%
rename from telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
rename to telephony/java/com/android/internal/telephony/ISmsImplBase.java
index cc1d105..1cdf44d 100644
--- a/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 The Android Open Source Project
+/*
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,17 +12,19 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- *
  */
 
 package com.android.internal.telephony;
 
 import android.app.PendingIntent;
 import android.net.Uri;
-import java.lang.UnsupportedOperationException;
+
 import java.util.List;
 
-public class ISmsBaseImpl extends ISms.Stub {
+/**
+ * Base class for ISms that facilitates forward compatibility with new features.
+ */
+public class ISmsImplBase extends ISms.Stub {
 
     @Override
     public List<SmsRawData> getAllMessagesFromIccEfForSubscriber(int subId, String callingPkg) {
@@ -29,45 +32,42 @@
     }
 
     @Override
-    public boolean updateMessageOnIccEfForSubscriber(int subId, String callingPkg,
-             int messageIndex, int newStatus, byte[] pdu) throws UnsupportedOperationException {
+    public boolean updateMessageOnIccEfForSubscriber(int subId, String callingPkg, int messageIndex,
+            int newStatus, byte[] pdu) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean copyMessageToIccEfForSubscriber(int subId, String callingPkg, int status,
-            byte[] pdu, byte[] smsc) throws UnsupportedOperationException {
+            byte[] pdu, byte[] smsc) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendDataForSubscriber(int subId, String callingPkg, String destAddr,
             String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
-            PendingIntent deliveryIntent) throws UnsupportedOperationException {
+            PendingIntent deliveryIntent) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendDataForSubscriberWithSelfPermissions(int subId, String callingPkg,
-            String destAddr, String scAddr, int destPort, byte[] data,
-            PendingIntent sentIntent, PendingIntent deliveryIntent)
-            throws UnsupportedOperationException {
+            String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
+            PendingIntent deliveryIntent) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendTextForSubscriber(int subId, String callingPkg, String destAddr,
             String scAddr, String text, PendingIntent sentIntent,
-            PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)
-            throws UnsupportedOperationException {
+            PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendTextForSubscriberWithSelfPermissions(int subId, String callingPkg,
             String destAddr, String scAddr, String text, PendingIntent sentIntent,
-            PendingIntent deliveryIntent, boolean persistMessage)
-            throws UnsupportedOperationException {
+            PendingIntent deliveryIntent, boolean persistMessage) {
         throw new UnsupportedOperationException();
     }
 
@@ -75,15 +75,13 @@
     public void sendTextForSubscriberWithOptions(int subId, String callingPkg, String destAddr,
             String scAddr, String text, PendingIntent sentIntent,
             PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp,
-            int priority, boolean expectMore, int validityPeriod)
-            throws UnsupportedOperationException {
+            int priority, boolean expectMore, int validityPeriod) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void injectSmsPduForSubscriber(
-            int subId, byte[] pdu, String format, PendingIntent receivedIntent)
-            throws UnsupportedOperationException {
+            int subId, byte[] pdu, String format, PendingIntent receivedIntent) {
         throw new UnsupportedOperationException();
     }
 
@@ -91,8 +89,7 @@
     public void sendMultipartTextForSubscriber(int subId, String callingPkg,
             String destinationAddress, String scAddress,
             List<String> parts, List<PendingIntent> sentIntents,
-            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)
-            throws UnsupportedOperationException {
+            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
         throw new UnsupportedOperationException();
     }
 
@@ -101,99 +98,94 @@
             String destinationAddress, String scAddress,
             List<String> parts, List<PendingIntent> sentIntents,
             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
-            int priority, boolean expectMore, int validityPeriod)
-            throws UnsupportedOperationException {
+            int priority, boolean expectMore, int validityPeriod) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean enableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
-            throws UnsupportedOperationException {
+    public boolean enableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean disableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
-            throws UnsupportedOperationException {
+    public boolean disableCellBroadcastForSubscriber(int subId, int messageIdentifier,
+            int ranType) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean enableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
-            int endMessageId, int ranType) throws UnsupportedOperationException {
+            int endMessageId, int ranType) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean disableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
-            int endMessageId, int ranType) throws UnsupportedOperationException {
+            int endMessageId, int ranType) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public int getPremiumSmsPermission(String packageName) throws UnsupportedOperationException {
+    public int getPremiumSmsPermission(String packageName) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public int getPremiumSmsPermissionForSubscriber(int subId, String packageName)
-            throws UnsupportedOperationException {
+    public int getPremiumSmsPermissionForSubscriber(int subId, String packageName) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public void setPremiumSmsPermission(String packageName, int permission) throws UnsupportedOperationException {
+    public void setPremiumSmsPermission(String packageName, int permission) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void setPremiumSmsPermissionForSubscriber(int subId, String packageName,
-            int permission) throws UnsupportedOperationException {
+            int permission) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean isImsSmsSupportedForSubscriber(int subId) throws UnsupportedOperationException {
+    public boolean isImsSmsSupportedForSubscriber(int subId) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean isSmsSimPickActivityNeeded(int subId) throws UnsupportedOperationException {
+    public boolean isSmsSimPickActivityNeeded(int subId) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public int getPreferredSmsSubscription() throws UnsupportedOperationException {
+    public int getPreferredSmsSubscription() {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public String getImsSmsFormatForSubscriber(int subId) throws UnsupportedOperationException {
+    public String getImsSmsFormatForSubscriber(int subId) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean isSMSPromptEnabled() throws UnsupportedOperationException {
+    public boolean isSMSPromptEnabled() {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendStoredText(int subId, String callingPkg, Uri messageUri, String scAddress,
-            PendingIntent sentIntent, PendingIntent deliveryIntent)
-            throws UnsupportedOperationException {
+            PendingIntent sentIntent, PendingIntent deliveryIntent) {
         throw new UnsupportedOperationException();
     }
 
     @Override
     public void sendStoredMultipartText(int subId, String callingPkg, Uri messageUri,
-                String scAddress, List<PendingIntent> sentIntents,
-                List<PendingIntent> deliveryIntents) throws UnsupportedOperationException {
+            String scAddress, List<PendingIntent> sentIntents,
+            List<PendingIntent> deliveryIntents) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent)
-            throws UnsupportedOperationException {
+    public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/tests/ActivityViewTest/Android.mk b/tests/ActivityViewTest/Android.mk
new file mode 100644
index 0000000..9c80764
--- /dev/null
+++ b/tests/ActivityViewTest/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := ActivityViewTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
new file mode 100644
index 0000000..de54cc9
--- /dev/null
+++ b/tests/ActivityViewTest/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.google.android.test.activityview">
+    <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
+    <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+
+    <uses-sdk android:targetSdkVersion="27"/>
+    <application android:label="ActivityViewTest">
+        <activity android:name=".ActivityViewMainActivity"
+                  android:label="AV Main"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".ActivityViewActivity"
+                  android:label="AV"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
+
+        <activity android:name=".ActivityViewResizeActivity"
+                  android:label="AV Resize"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
+
+        <activity android:name=".ActivityViewScrollActivity"
+                  android:label="AV Scroll"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
+
+        <activity android:name=".ActivityViewTestActivity"
+                  android:resizeableActivity="true"
+                  android:theme="@*android:style/Theme.NoTitleBar"
+                  android:exported="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_activity.xml
new file mode 100644
index 0000000..67c01f8
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_activity.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="#cfd8dc">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/activity_launch_button"
+            android:layout_width="200dp"
+            android:layout_height="wrap_content"
+            android:text="Launch test activity" />
+
+        <Button
+            android:id="@+id/activity_pick_launch_button"
+            android:layout_width="200dp"
+            android:layout_height="wrap_content"
+            android:text="Launch from picker" />
+
+    </LinearLayout>
+
+    <ActivityView
+        android:id="@+id/activity_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
new file mode 100644
index 0000000..ba2e911
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/activity_view_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Test ActivityView"
+        android:textAllCaps="false"/>
+
+    <Button
+        android:id="@+id/scroll_activity_view_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Test Scroll ActivityView"
+        android:textAllCaps="false"/>
+
+    <Button
+        android:id="@+id/resize_activity_view_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Test Resize ActivityView"
+        android:textAllCaps="false"/>
+
+</LinearLayout>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
new file mode 100644
index 0000000..18d86e3
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="#cfd8dc">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/activity_launch_button"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:text="Launch" />
+
+        <Button
+            android:id="@+id/activity_resize_button"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:text="Resize" />
+    </LinearLayout>
+
+    <SeekBar
+        android:id="@+id/activity_view_seek_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <ActivityView
+        android:id="@+id/activity_view"
+        android:layout_width="match_parent"
+        android:layout_height="600dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
new file mode 100644
index 0000000..879c2c20
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical" android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/activity_launch_button"
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:text="Launch" />
+
+    <ScrollView
+        android:id="@+id/activity_view_host_scroll_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:color="#cfd8dc">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="300dp"
+                android:layout_gravity="center_horizontal"
+                android:background="#eeeeee" />
+
+            <ActivityView
+                android:id="@+id/activity_view"
+                android:layout_width="match_parent"
+                android:layout_height="300dp"
+                android:background="#fce4ec" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="300dp"
+                android:layout_gravity="center_horizontal"
+                android:background="#eeeeee" />
+        </LinearLayout>
+    </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
new file mode 100644
index 0000000..f7ec562
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="#ffe0b2">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:orientation="vertical"
+        android:background="#00000000" >
+        <TextView
+            android:id="@+id/test_activity_title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textColor="@android:color/black"
+            android:background="#00000000"
+            android:gravity="center" />
+        <TextView
+            android:id="@+id/test_activity_touch_state"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textColor="@android:color/black"
+            android:background="#00000000"
+            android:gravity="center" />
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/test_activity_width_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textColor="@android:color/black"
+        android:background="#00000000"
+        android:gravity="center" />
+
+    <TextView
+        android:id="@+id/test_activity_height_text"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true"
+        android:textColor="@android:color/black"
+        android:background="#00000000"
+        android:gravity="center" />
+
+    <View
+        android:id="@+id/touch_intercept_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#00000000"
+    />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
new file mode 100644
index 0000000..1548d6e
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Button;
+
+public class ActivityViewActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_activity);
+
+        final ActivityView activityView = findViewById(R.id.activity_view);
+        final Button launchButton = findViewById(R.id.activity_launch_button);
+        launchButton.setOnClickListener(v -> {
+            final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            activityView.startActivity(intent);
+        });
+        final Button pickActivityLaunchButton = findViewById(R.id.activity_pick_launch_button);
+        pickActivityLaunchButton.setOnClickListener(v -> {
+            final Intent intent = Intent.makeMainActivity(null);
+            final Intent chooser = Intent.createChooser(intent,
+                    "Pick an app to launch in ActivityView");
+            if (intent.resolveActivity(getPackageManager()) != null) {
+                chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                activityView.startActivity(chooser);
+            }
+        });
+    }
+}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
new file mode 100644
index 0000000..66f0c6a
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class ActivityViewMainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_main_activity);
+
+        findViewById(R.id.activity_view_button).setOnClickListener(
+                v -> startActivity(new Intent(this, ActivityViewActivity.class)));
+
+        findViewById(R.id.scroll_activity_view_button).setOnClickListener(
+                v -> startActivity(new Intent(this, ActivityViewScrollActivity.class)));
+
+        findViewById(R.id.resize_activity_view_button).setOnClickListener(
+                v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
+    }
+}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
new file mode 100644
index 0000000..8860a77
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+
+public class ActivityViewResizeActivity extends Activity {
+    private static final int SMALL_SIZE = 600;
+    private static final int LARGE_SIZE = 1200;
+
+    private ActivityView mActivityView;
+
+    private boolean mFlipSize;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_resize_activity);
+
+        mActivityView = findViewById(R.id.activity_view);
+
+        final Button launchButton = findViewById(R.id.activity_launch_button);
+        launchButton.setOnClickListener(v -> {
+            final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            mActivityView.startActivity(intent);
+        });
+        final Button resizeButton = findViewById(R.id.activity_resize_button);
+        if (resizeButton != null) {
+            resizeButton.setOnClickListener(v -> {
+                LinearLayout.LayoutParams params =
+                        (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
+                params.height = mFlipSize ? SMALL_SIZE : LARGE_SIZE;
+                mFlipSize = !mFlipSize;
+                mActivityView.setLayoutParams(params);
+            });
+        }
+        final SeekBar seekBar = findViewById(R.id.activity_view_seek_bar);
+        if (seekBar != null) {
+            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                @Override
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    final LinearLayout.LayoutParams params =
+                            (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
+                    params.height = SMALL_SIZE + progress * 10;
+                    mActivityView.setLayoutParams(params);
+                }
+
+                @Override
+                public void onStartTrackingTouch(SeekBar seekBar) {
+                }
+
+                @Override
+                public void onStopTrackingTouch(SeekBar seekBar) {
+                }
+            });
+        }
+    }
+}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
new file mode 100644
index 0000000..5654366
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+public class ActivityViewScrollActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_scroll_activity);
+
+        final ActivityView activityView = findViewById(R.id.activity_view);
+        final Button launchButton = findViewById(R.id.activity_launch_button);
+        launchButton.setOnClickListener(v -> {
+            final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            activityView.startActivity(intent);
+        });
+        findViewById(R.id.activity_view_host_scroll_view).setOnScrollChangeListener(
+                (View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
+                        -> activityView.onLocationChanged());
+    }
+}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
new file mode 100644
index 0000000..0d62786
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.TextView;
+
+public class ActivityViewTestActivity extends Activity implements View.OnTouchListener {
+
+    private TextView mTextView;
+    private TextView mWidthTextView;
+    private TextView mHeightTextView;
+    private TextView mTouchStateTextView;
+    private View mTouchInterceptView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_test_activity);
+
+        mTextView = findViewById(R.id.test_activity_title);
+        mWidthTextView = findViewById(R.id.test_activity_width_text);
+        mHeightTextView = findViewById(R.id.test_activity_height_text);
+        mTouchStateTextView = findViewById(R.id.test_activity_touch_state);
+        mTouchInterceptView = findViewById(R.id.touch_intercept_view);
+        mTouchInterceptView.setOnTouchListener(this);
+        ViewTreeObserver viewTreeObserver = mTouchInterceptView.getViewTreeObserver();
+        if (viewTreeObserver.isAlive()) {
+            viewTreeObserver.addOnGlobalLayoutListener(this::updateDimensionTexts);
+        }
+        updateStateText("CREATED");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        updateStateText("STARTED");
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        updateStateText("RESUMED");
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        updateStateText("PAUSED");
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        updateStateText("STOPPED");
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateDimensionTexts();
+    }
+
+    private void updateStateText(String state) {
+        mTextView.setText(state);
+    }
+
+    private void updateDimensionTexts() {
+        mWidthTextView.setText("" + mTouchInterceptView.getWidth());
+        mHeightTextView.setText("" + mTouchInterceptView.getHeight());
+    }
+
+    private void updateTouchState(MotionEvent event) {
+        switch (event.getAction()) {
+            case ACTION_DOWN:
+            case ACTION_MOVE:
+                mTouchStateTextView.setText("[" + event.getX() + "," + event.getY() + "]");
+                break;
+            case ACTION_UP:
+            case ACTION_CANCEL:
+                mTouchStateTextView.setText("");
+                break;
+        }
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        updateTouchState(event);
+        return true;
+    }
+}
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 8c1fa9a..36b5578 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -690,10 +690,6 @@
     return 0;
   }
 
-  bool IsAutoNamespace() override {
-    return false;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(CompileContext);
 
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 4b82eef..d57eaa1 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -311,10 +311,6 @@
     return 0u;
   }
 
-  bool IsAutoNamespace() override {
-    return false;
-  }
-
   bool verbose_ = false;
   std::string package_;
 
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 7875a2b..262f4fc4e 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -65,10 +65,6 @@
     return 0;
   }
 
-  bool IsAutoNamespace() override {
-    return false;
-  }
-
  private:
   std::string empty_;
   StdErrDiagnostics diagnostics_;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 717e757..8b1f672 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -292,10 +292,6 @@
     return 0;
   }
 
-  bool IsAutoNamespace() override {
-    return false;
-  }
-
  private:
   StdErrDiagnostics diagnostics_;
   bool verbose_ = false;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1d508d9..c94b847 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -137,14 +137,6 @@
     min_sdk_version_ = minSdk;
   }
 
-  bool IsAutoNamespace() override {
-    return auto_namespace_;
-  }
-
-  void SetAutoNamespace(bool val) {
-    auto_namespace_ = val;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LinkContext);
 
@@ -156,7 +148,6 @@
   SymbolTable symbols_;
   bool verbose_ = false;
   int min_sdk_version_ = 0;
-  bool auto_namespace_ = false;
 };
 
 // A custom delegate that generates compatible pre-O IDs for use with feature splits.
@@ -2042,15 +2033,6 @@
     options_.output_format = OutputFormat::kProto;
   }
 
-  if (options_.auto_namespace_static_lib) {
-    if (!static_lib_) {
-      context.GetDiagnostics()->Error(
-          DiagMessage() << "--auto-namespace-static-lib can only be used with --static-lib");
-      return 1;
-    }
-    context.SetAutoNamespace(true);
-  }
-
   if (package_id_) {
     if (context.GetPackageType() != PackageType::kApp) {
       context.GetDiagnostics()->Error(
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 434475e..fb8796f 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -64,7 +64,6 @@
 
   // Static lib options.
   bool no_static_lib_packages = false;
-  bool auto_namespace_static_lib = false;
 
   // AndroidManifest.xml massaging options.
   ManifestFixerOptions manifest_fixer_options;
@@ -188,10 +187,6 @@
     AddOptionalSwitch("--no-static-lib-packages",
         "Merge all library resources under the app's package.",
         &options_.no_static_lib_packages);
-    AddOptionalSwitch("--auto-namespace-static-lib",
-        "Automatically namespace resource references when building a static\n"
-            "library.",
-        &options_.auto_namespace_static_lib);
     AddOptionalSwitch("--non-final-ids",
         "Generates R.java without the final modifier. This is implied when\n"
             "--static-lib is specified.",
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index b4cba8c..47288ec 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -104,10 +104,6 @@
     return sdk_version_;
   }
 
-  bool IsAutoNamespace() override {
-    return false;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(OptimizeContext);
 
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/Android.mk b/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/Android.mk
deleted file mode 100644
index 91716b9..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestAutoNamespace_LibOne
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_AAPT_NAMESPACES := true
-LOCAL_AAPT_FLAGS := --auto-namespace-static-lib
-# We need this to compile the Java sources of AaptTestStaticLib_LibTwo using javac.
-LOCAL_JAR_EXCLUDE_FILES := none
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/AndroidManifest.xml
deleted file mode 100644
index f585840..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest package="com.example.android.aapt2.autonamespace.staticlib.one" />
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/res/values/values.xml b/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/res/values/values.xml
deleted file mode 100644
index 3e57b0f..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/res/values/values.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <!-- An attribute from StaticLibOne -->
-    <attr name="StaticLibOne_attr" format="string" />
-
-    <string name="Foo">Foo</string>
-
-    <declare-styleable name="Widget">
-        <attr name="StaticLibOne_attr" />
-        <attr name="android:text" />
-    </declare-styleable>
-</resources>
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/src/com/example/android/aapt2/autonamespace/staticlib/one/StaticLibOne.java b/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/src/com/example/android/aapt2/autonamespace/staticlib/one/StaticLibOne.java
deleted file mode 100644
index 886d48c..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibOne/src/com/example/android/aapt2/autonamespace/staticlib/one/StaticLibOne.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.example.android.aapt2.autonamespace.staticlib.one;
-
-public class StaticLibOne { public static int FooId = R.string.Foo; }
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/Android.mk b/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/Android.mk
deleted file mode 100644
index c85496d..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestAutoNamespace_LibTwo
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestAutoNamespace_LibOne
-LOCAL_AAPT_NAMESPACES := true
-LOCAL_AAPT_FLAGS := --auto-namespace-static-lib
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/AndroidManifest.xml
deleted file mode 100644
index 8d3c506..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest package="com.example.android.aapt2.autonamespace.staticlib.two" />
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/values/values.xml b/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/values/values.xml
deleted file mode 100644
index c532387..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/values/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <string name="FooBar">@string/Foo</string>
-</resources>
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/src/com/example/android/aapt2/autonamespace/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/src/com/example/android/aapt2/autonamespace/staticlib/two/StaticLibTwo.java
deleted file mode 100644
index 323f53a..0000000
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/src/com/example/android/aapt2/autonamespace/staticlib/two/StaticLibTwo.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.example.android.aapt2.autonamespace.staticlib.two;
-
-public class StaticLibTwo {
-  // IDs from StaticLibOne
-  public static int FooId = com.example.android.aapt2.autonamespace.staticlib.one.R.string.Foo;
-
-  // IDs from StaticLibTwo
-  public static int FooBarId = R.string.FooBar;
-  public static int LayoutId = R.layout.layout_two;
-}
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 28e71cc..3a5d585 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -80,7 +80,7 @@
 
       // Find the attribute in the symbol table and check if it is visible from this callsite.
       const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
-          transformed_reference, callsite_, symbols_, context_->IsAutoNamespace(), &err_str);
+          transformed_reference, callsite_, symbols_, &err_str);
       if (symbol) {
         // Assign our style key the correct ID. The ID may not exist.
         entry.key.id = symbol->id;
@@ -202,18 +202,12 @@
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
                                                           const CallSite& callsite,
-                                                          SymbolTable* symbols,
-                                                          bool auto_namespace) {
+                                                          SymbolTable* symbols) {
   if (reference.name) {
     const ResourceName& name = reference.name.value();
     if (name.package.empty()) {
       // Use the callsite's package name if no package name was defined.
-      const SymbolTable::Symbol* local_symbol =
-          symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
-      if (!auto_namespace || local_symbol) {
-        return local_symbol;
-      }
-      return symbols->FindByNameInAnyPackage(name);
+      return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
     }
     return symbols->FindByName(name);
   } else if (reference.id) {
@@ -226,9 +220,8 @@
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
                                                                          const CallSite& callsite,
                                                                          SymbolTable* symbols,
-                                                                         bool auto_namespace,
                                                                          std::string* out_error) {
-  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols, auto_namespace);
+  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols);
   if (!symbol) {
     if (out_error) *out_error = "not found";
     return nullptr;
@@ -242,10 +235,10 @@
 }
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
-    const Reference& reference, const CallSite& callsite, SymbolTable* symbols, bool auto_namespace,
+    const Reference& reference, const CallSite& callsite, SymbolTable* symbols,
     std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveSymbolCheckVisibility(reference, callsite, symbols, auto_namespace, out_error);
+      ResolveSymbolCheckVisibility(reference, callsite, symbols, out_error);
   if (!symbol) {
     return nullptr;
   }
@@ -260,10 +253,9 @@
 Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
                                                                const CallSite& callsite,
                                                                SymbolTable* symbols,
-                                                               bool auto_namespace,
                                                                std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveAttributeCheckVisibility(reference, callsite, symbols, auto_namespace, out_error);
+      ResolveAttributeCheckVisibility(reference, callsite, symbols, out_error);
   if (!symbol) {
     return {};
   }
@@ -341,8 +333,8 @@
   xml::ResolvePackage(decls, &transformed_reference);
 
   std::string err_str;
-  const SymbolTable::Symbol* s = ResolveSymbolCheckVisibility(
-      transformed_reference, callsite, symbols, context->IsAutoNamespace(), &err_str);
+  const SymbolTable::Symbol* s =
+      ResolveSymbolCheckVisibility(transformed_reference, callsite, symbols, &err_str);
   if (s) {
     // The ID may not exist. This is fine because of the possibility of building
     // against libraries without assigned IDs.
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index 7887915..b0b4945 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -36,12 +36,10 @@
   ReferenceLinker() = default;
 
   // Performs name mangling and looks up the resource in the symbol table. Uses the callsite's
-  // package if the reference has no package name defined (implicit), or if auto_namespace is
-  // set try looking in all avaliable packages for a symbol of that name.
+  // package if the reference has no package name defined (implicit).
   // Returns nullptr if the symbol was not found.
   static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference,
-                                                  const CallSite& callsite, SymbolTable* symbols,
-                                                  bool auto_namespace);
+                                                  const CallSite& callsite, SymbolTable* symbols);
 
   // Performs name mangling and looks up the resource in the symbol table. If the symbol is not
   // visible by the reference at the callsite, nullptr is returned.
@@ -49,7 +47,6 @@
   static const SymbolTable::Symbol* ResolveSymbolCheckVisibility(const Reference& reference,
                                                                  const CallSite& callsite,
                                                                  SymbolTable* symbols,
-                                                                 bool auto_namespace,
                                                                  std::string* out_error);
 
   // Same as ResolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute.
@@ -57,14 +54,13 @@
   static const SymbolTable::Symbol* ResolveAttributeCheckVisibility(const Reference& reference,
                                                                     const CallSite& callsite,
                                                                     SymbolTable* symbols,
-                                                                    bool auto_namespace,
                                                                     std::string* out_error);
 
   // Resolves the attribute reference and returns an xml::AaptAttribute if successful.
   // If resolution fails, outError holds the error message.
   static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference,
                                                        const CallSite& callsite,
-                                                       SymbolTable* symbols, bool auto_namespace,
+                                                       SymbolTable* symbols,
                                                        std::string* out_error);
 
   // Writes the resource name to the DiagMessage, using the
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 0b7b1ce..be38b96 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -267,7 +267,7 @@
   std::string error;
   const CallSite call_site{"com.app.test"};
   const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
-      *test::BuildReference("com.app.test:string/foo"), call_site, &table, false, &error);
+      *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error);
   ASSERT_THAT(symbol, NotNull());
   EXPECT_TRUE(error.empty());
 }
@@ -285,13 +285,13 @@
   std::string error;
   const CallSite call_site{"com.app.ext"};
 
-  EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(*test::BuildReference("com.app.test:attr/foo"),
-                                                    call_site, &table, false, &error));
+  EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
+      *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error));
   EXPECT_FALSE(error.empty());
 
   error = "";
   ASSERT_TRUE(ReferenceLinker::CompileXmlAttribute(
-      *test::BuildReference("com.app.test:attr/public_foo"), call_site, &table, false, &error));
+      *test::BuildReference("com.app.test:attr/public_foo"), call_site, &table, &error));
   EXPECT_TRUE(error.empty());
 }
 
@@ -303,74 +303,19 @@
                          .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001))
                          .Build());
 
-  const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(
-      *test::BuildReference("string/foo"), CallSite{"com.app.test"}, &table, false);
+  const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
+                                                                CallSite{"com.app.test"}, &table);
   ASSERT_THAT(s, NotNull());
   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
 
   s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
-                                     &table, false);
+                                     &table);
   ASSERT_THAT(s, NotNull());
   EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
 
   EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
-                                             CallSite{"com.app.bad"}, &table, false),
+                                             CallSite{"com.app.bad"}, &table),
               IsNull());
 }
 
-TEST(ReferenceLinkerTest, AutomaticNamespace) {
-  NameMangler mangler(NameManglerPolicy{"com.example.thislib"});
-  SymbolTable table(&mangler);
-  table.AppendSource(
-      test::StaticSymbolSourceBuilder()
-          .AddSymbol("com.example.thislib:string/thislib_string", ResourceId(0x7f010006))
-          .AddSymbol("com.example.thislib:string/explicit_override_string", ResourceId(0x7f010007))
-          .Build());
-  // Lib2 is higher priority than lib1
-  table.AppendSource(
-      test::StaticSymbolSourceBuilder()
-          .AddSymbol("com.example.lib2:string/lib2_string", ResourceId(0x7f010003))
-          .AddSymbol("com.example.lib2:string/explicit_override_string", ResourceId(0x7f010004))
-          .AddSymbol("com.example.lib2:string/implicit_override_string", ResourceId(0x7f010005))
-          .Build());
-  table.AppendSource(
-      test::StaticSymbolSourceBuilder()
-          .AddSymbol("com.example.lib1:string/explicit_override_string", ResourceId(0x7f010001))
-          .AddSymbol("com.example.lib1:string/implicit_override_string", ResourceId(0x7f010002))
-          .Build());
-
-  // Sanity test: Local references are still fine.
-  const SymbolTable::Symbol* s =
-      ReferenceLinker::ResolveSymbol(*test::BuildReference("string/thislib_string"),
-                                     CallSite{"com.example.thislib"}, &table, true);
-  ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010006)));
-
-  // Local references are fine, even if clash with remote ones.
-  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/explicit_override_string"),
-                                     CallSite{"com.example.thislib"}, &table, true);
-  ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010007)));
-
-  // An unqualified reference to lib2 is rewritten
-  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/lib2_string"),
-                                     CallSite{"com.example.thislib"}, &table, true);
-  ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010003)));
-
-  // Qualified references are left alone.
-  s = ReferenceLinker::ResolveSymbol(
-      *test::BuildReference("com.example.lib2:string/explicit_override_string"),
-      CallSite{"com.example.thislib"}, &table, true);
-  ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010004)));
-
-  // Implicit overrides respect priority ordering.
-  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/implicit_override_string"),
-                                     CallSite{"com.example.thislib"}, &table, true);
-  ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010005)));
-
-  //
-}
 }  // namespace aapt
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 420a127..160ff92 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -97,8 +97,8 @@
         attr_ref.private_reference = maybe_package.value().private_namespace;
 
         std::string err_str;
-        attr.compiled_attribute = ReferenceLinker::CompileXmlAttribute(
-            attr_ref, callsite_, symbols_, context_->IsAutoNamespace(), &err_str);
+        attr.compiled_attribute =
+            ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, symbols_, &err_str);
 
         if (!attr.compiled_attribute) {
           DiagMessage error_msg(source);
diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp
index d321f8f..ef99355 100644
--- a/tools/aapt2/link/XmlReferenceLinker_test.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp
@@ -18,7 +18,6 @@
 
 #include "test/Test.h"
 
-using ::testing::Eq;
 using ::testing::IsNull;
 using ::testing::NotNull;
 
@@ -71,29 +70,12 @@
                                                 .Build())
                            .AddPublicSymbol("com.app.test:attr/attr", ResourceId(0x7f010002),
                                             test::AttributeBuilder().Build())
-                           .AddPublicSymbol("com.app.lib:string/lib_string", ResourceId(0x7f020003))
                            .Build())
                    .Build();
-
-    auto_namespace_context_ =
-        test::ContextBuilder()
-            .SetCompilationPackage("com.app.test")
-            .SetNameManglerPolicy(NameManglerPolicy{"com.app.test", {"com.android.support"}})
-            .SetAutoNamespace(true)
-            .AddSymbolSource(
-                test::StaticSymbolSourceBuilder()
-                    .AddPublicSymbol("android:attr/text", ResourceId(0x01010003),
-                                     test::AttributeBuilder()
-                                         .SetTypeMask(android::ResTable_map::TYPE_STRING)
-                                         .Build())
-                    .AddPublicSymbol("com.app.lib:string/lib_string", ResourceId(0x7f020003))
-                    .Build())
-            .Build();
   }
 
  protected:
   std::unique_ptr<IAaptContext> context_;
-  std::unique_ptr<IAaptContext> auto_namespace_context_;
 };
 
 TEST_F(XmlReferenceLinkerTest, LinkBasicAttributes) {
@@ -213,31 +195,6 @@
   EXPECT_EQ(make_value(ResourceId(0x7f020001)), ref->id);
 }
 
-TEST_F(XmlReferenceLinkerTest, LinkAutoNamespaceResReference) {
-  std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"(
-      <View
-          xmlns:android="http://schemas.android.com/apk/res/android"
-          android:text="@string/lib_string" />)");
-
-  XmlReferenceLinker linker;
-  // Should not link with auto-namespace support disabled.
-  ASSERT_FALSE(linker.Consume(context_.get(), doc.get()));
-  // Should link with auto-namespace enabled.
-  ASSERT_TRUE(linker.Consume(auto_namespace_context_.get(), doc.get()));
-
-  xml::Element* view_el = doc->root.get();
-  ASSERT_THAT(view_el, NotNull());
-
-  xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "text");
-  ASSERT_THAT(xml_attr, NotNull());
-  ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010003)), xml_attr->compiled_attribute.value().id);
-  Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get());
-  ASSERT_THAT(ref, NotNull());
-  ASSERT_TRUE(ref->name);
-  EXPECT_EQ(make_value(ResourceId(0x7f020003)), ref->id);
-}
-
 TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) {
   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"(
       <View xmlns:app="http://schemas.android.com/apk/res/android" app:attr="@app:id/id">
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index a931343..e92c121 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -99,10 +99,6 @@
         util::make_unique<SourcePathDiagnostics>(Source{source}, context_->GetDiagnostics());
   }
 
-  bool IsAutoNamespace() override {
-    return context_->IsAutoNamespace();
-  }
-
  private:
   IAaptContext* context_;
   std::unique_ptr<SourcePathDiagnostics> source_diag_;
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index a3a7719..30dad802 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -50,7 +50,6 @@
   virtual NameMangler* GetNameMangler() = 0;
   virtual bool IsVerbose() = 0;
   virtual int GetMinSdkVersion() = 0;
-  virtual bool IsAutoNamespace() = 0;
 };
 
 struct IResourceTableConsumer {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index ef2e448..fc4c9b5 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -114,16 +114,6 @@
   return shared_symbol.get();
 }
 
-const SymbolTable::Symbol* SymbolTable::FindByNameInAnyPackage(const ResourceName& name) {
-  for (auto& source : sources_) {
-    std::string package = source->GetPackageForSymbol(name);
-    if (!package.empty()) {
-      return FindByName(ResourceName(package, name.type, name.entry));
-    }
-  }
-  return {};
-}
-
 const SymbolTable::Symbol* SymbolTable::FindById(const ResourceId& id) {
   if (const std::shared_ptr<Symbol>& s = id_cache_.get(id)) {
     return s.get();
@@ -221,25 +211,6 @@
   return symbol;
 }
 
-std::string ResourceTableSymbolSource::GetPackageForSymbol(const ResourceName& name) {
-  for (auto& package : table_->packages) {
-    ResourceTableType* type = package->FindType(name.type);
-    if (type == nullptr) {
-      continue;
-    }
-    ResourceEntry* entry = type->FindEntry(name.entry);
-    if (entry == nullptr) {
-      continue;
-    }
-    return package->name;
-  }
-  if (name.type == ResourceType::kAttr) {
-    // Recurse and try looking up a private attribute.
-    return GetPackageForSymbol(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
-  }
-  return {};
-}
-
 bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
   int32_t cookie = 0;
   return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie);
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index c798cbb..51a2e37 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -89,13 +89,6 @@
   // results are stored in a cache which may evict entries on subsequent calls.
   const Symbol* FindByName(const ResourceName& name);
 
-  // Finds the symbol from any package, for use as part of automatic conversion to namespaces.
-  // This returns the symbol from the highest priority package,
-  // which mimics the behavior of the resource merger and overlays.
-  // NOTE: Never hold on to the result between calls to FindByXXX. The
-  // results are stored in a cache which may evict entries on subsequent calls.
-  const Symbol* FindByNameInAnyPackage(const ResourceName& name);
-
   // NOTE: Never hold on to the result between calls to FindByXXX. The
   // results are stored in a cache which may evict entries on subsequent calls.
   const Symbol* FindById(const ResourceId& id);
@@ -160,11 +153,6 @@
 
   virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) = 0;
-  // Finds the name of a symbol from any package,
-  // for use as part of automatic conversion to namespaces.
-  // This returns the symbol from the highest priority package,
-  // which mimics the behavior of the resource merger and overlays.
-  virtual std::string GetPackageForSymbol(const ResourceName& name) = 0;
   virtual std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) = 0;
 
   // Default implementation tries the name if it exists, else the ID.
@@ -189,7 +177,6 @@
   std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) override;
 
-  std::string GetPackageForSymbol(const ResourceName& name) override;
   std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override {
     return {};
   }
@@ -210,9 +197,6 @@
 
   std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) override;
-  std::string GetPackageForSymbol(const ResourceName& name) override {
-    return {};
-  }
   std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override;
   std::unique_ptr<SymbolTable::Symbol> FindByReference(
       const Reference& ref) override;
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index df40b26..1f59d70 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -120,39 +120,4 @@
   EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.other:id/foo")), IsNull());
 }
 
-TEST(SymbolTableTest, FindByNameInAnyPackage) {
-  // This represents lib3 --depends-on--> lib2 --depends-on--> lib1
-
-  NameMangler mangler(NameManglerPolicy{"com.example.lib3"});
-  SymbolTable symbol_table(&mangler);
-  // Lib2 has higher precedence than lib1, as it is closer to the current library (lib3)
-  // in the dependency graph.
-
-  symbol_table.AppendSource(test::StaticSymbolSourceBuilder()
-                                .AddPublicSymbol("com.example.lib1:string/foo", ResourceId())
-                                .AddSymbol("com.example.lib1:attr/foo", ResourceId(),
-                                           test::AttributeBuilder()
-                                               .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
-                                               .AddItem("one", 0x01)
-                                               .AddItem("two", 0x02)
-                                               .Build())
-                                .Build());
-  symbol_table.PrependSource(test::StaticSymbolSourceBuilder()
-                                 .AddPublicSymbol("com.example.lib2:string/foo", ResourceId())
-                                 .Build());
-
-  // Sanity test
-  EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("string/foo")), IsNull());
-
-  // Test public symbol resolution
-  const SymbolTable::Symbol* const found_string =
-      symbol_table.FindByNameInAnyPackage(test::ParseNameOrDie("string/foo"));
-  ASSERT_THAT(found_string, NotNull());
-
-  // Test attr resolution
-  const SymbolTable::Symbol* const found_attr =
-      symbol_table.FindByNameInAnyPackage(test::ParseNameOrDie("attr/foo"));
-  ASSERT_THAT(found_attr, NotNull());
-}
-
 }  // namespace aapt
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index a07d79f..0564db0 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -81,10 +81,6 @@
     return min_sdk_version_;
   }
 
-  bool IsAutoNamespace() override {
-    return auto_namespace_;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(Context);
 
@@ -97,7 +93,6 @@
   NameMangler name_mangler_;
   SymbolTable symbols_;
   int min_sdk_version_;
-  bool auto_namespace_;
 };
 
 class ContextBuilder {
@@ -132,11 +127,6 @@
     return *this;
   }
 
-  ContextBuilder& SetAutoNamespace(bool auto_namespace) {
-    context_->auto_namespace_ = auto_namespace;
-    return *this;
-  }
-
   std::unique_ptr<Context> Build() { return std::move(context_); }
 
  private:
@@ -182,15 +172,6 @@
       return nullptr;
     }
 
-    std::string GetPackageForSymbol(const ResourceName& name) override {
-      for (auto const& imap : name_map_) {
-        if (imap.first.type == name.type && imap.first.entry == name.entry) {
-          return imap.first.package;
-        }
-      }
-      return "";
-    }
-
     std::unique_ptr<SymbolTable::Symbol> FindById(ResourceId id) override {
       auto iter = id_map_.find(id);
       if (iter != id_map_.end()) {
diff --git a/tools/hiddenapi/class2greylist/Android.bp b/tools/hiddenapi/class2greylist/Android.bp
new file mode 100644
index 0000000..7b1233b
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_library_host {
+  name: "class2greylistlib",
+  srcs: ["src/**/*.java"],
+  static_libs: [
+    "commons-cli-1.2",
+    "apache-bcel",
+  ],
+}
+
+java_binary_host {
+  name: "class2greylist",
+  manifest: "src/class2greylist.mf",
+  static_libs: [
+    "class2greylistlib",
+  ],
+}
+
diff --git a/tools/hiddenapi/class2greylist/src/class2greylist.mf b/tools/hiddenapi/class2greylist/src/class2greylist.mf
new file mode 100644
index 0000000..ea3a3d9
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/src/class2greylist.mf
@@ -0,0 +1 @@
+Main-Class: com.android.class2greylist.Class2Greylist
diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java
new file mode 100644
index 0000000..6685752
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.class2greylist;
+
+import org.apache.bcel.Const;
+import org.apache.bcel.classfile.AnnotationEntry;
+import org.apache.bcel.classfile.DescendingVisitor;
+import org.apache.bcel.classfile.ElementValuePair;
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.FieldOrMethod;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+
+import java.util.Locale;
+
+/**
+ * Visits a JavaClass instance and pulls out all members annotated with a
+ * specific annotation. The signatures of such members are passed to {@link
+ * Status#greylistEntry(String)}. Any errors result in a call to {@link
+ * Status#error(String)}.
+ *
+ * If the annotation has a property "expectedSignature" the generated signature
+ * will be verified against the one specified there. If it differs, an error
+ * will be generated.
+ */
+public class AnnotationVisitor extends EmptyVisitor {
+
+    private static final String EXPECTED_SIGNATURE = "expectedSignature";
+
+    private final JavaClass mClass;
+    private final String mAnnotationType;
+    private final Status mStatus;
+    private final DescendingVisitor mDescendingVisitor;
+
+    public AnnotationVisitor(JavaClass clazz, String annotation, Status d) {
+        mClass = clazz;
+        mAnnotationType = annotation;
+        mStatus = d;
+        mDescendingVisitor = new DescendingVisitor(clazz, this);
+    }
+
+    public void visit() {
+        mStatus.debug("Visit class %s", mClass.getClassName());
+        mDescendingVisitor.visit();
+    }
+
+    private static String getClassDescriptor(JavaClass clazz) {
+        // JavaClass.getName() returns the Java-style name (with . not /), so we must fetch
+        // the original class name from the constant pool.
+        return clazz.getConstantPool().getConstantString(
+                clazz.getClassNameIndex(), Const.CONSTANT_Class);
+    }
+
+    @Override
+    public void visitMethod(Method method) {
+        visitMember(method, "L%s;->%s%s");
+    }
+
+    @Override
+    public void visitField(Field field) {
+        visitMember(field, "L%s;->%s:%s");
+    }
+
+    private void visitMember(FieldOrMethod member, String signatureFormatString) {
+        JavaClass definingClass = (JavaClass) mDescendingVisitor.predecessor();
+        mStatus.debug("Visit member %s : %s", member.getName(), member.getSignature());
+        for (AnnotationEntry a : member.getAnnotationEntries()) {
+            if (mAnnotationType.equals(a.getAnnotationType())) {
+                mStatus.debug("Method has annotation %s", mAnnotationType);
+                String signature = String.format(Locale.US, signatureFormatString,
+                        getClassDescriptor(definingClass), member.getName(), member.getSignature());
+                for (ElementValuePair property : a.getElementValuePairs()) {
+                    switch (property.getNameString()) {
+                        case EXPECTED_SIGNATURE:
+                            String expected = property.getValue().stringifyValue();
+                            if (!signature.equals(expected)) {
+                                error(definingClass, member,
+                                        "Expected signature does not match generated:\n"
+                                                + "Expected:  %s\n"
+                                                + "Generated: %s", expected, signature);
+                            }
+                            break;
+                    }
+                }
+                mStatus.greylistEntry(signature);
+            }
+        }
+    }
+
+    private void error(JavaClass clazz, FieldOrMethod member, String message, Object... args) {
+        StringBuilder error = new StringBuilder();
+        error.append(clazz.getSourceFileName())
+                .append(": ")
+                .append(clazz.getClassName())
+                .append(".")
+                .append(member.getName())
+                .append(": ")
+                .append(String.format(Locale.US, message, args));
+
+        mStatus.error(error.toString());
+    }
+
+}
diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java
new file mode 100644
index 0000000..bcccf4a
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.class2greylist;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PatternOptionBuilder;
+
+import java.io.IOException;
+
+/**
+ * Build time tool for extracting a list of members from jar files that have the @UsedByApps
+ * annotation, for building the greylist.
+ */
+public class Class2Greylist {
+
+    private static final String ANNOTATION_TYPE = "Landroid/annotation/UsedByApps;";
+
+    public static void main(String[] args) {
+        Options options = new Options();
+        options.addOption(OptionBuilder
+                .withLongOpt("debug")
+                .hasArgs(0)
+                .withDescription("Enable debug")
+                .create("d"));
+        options.addOption(OptionBuilder
+                .withLongOpt("help")
+                .hasArgs(0)
+                .withDescription("Show this help")
+                .create("h"));
+
+        CommandLineParser parser = new GnuParser();
+        CommandLine cmd;
+
+        try {
+            cmd = parser.parse(options, args);
+        } catch (ParseException e) {
+            System.err.println(e.getMessage());
+            help(options);
+            return;
+        }
+        if (cmd.hasOption('h')) {
+            help(options);
+        }
+
+        String[] jarFiles = cmd.getArgs();
+        if (jarFiles.length == 0) {
+            System.err.println("Error: no jar files specified.");
+            help(options);
+        }
+
+        Status status = new Status(cmd.hasOption('d'));
+
+        for (String jarFile : jarFiles) {
+            status.debug("Processing jar file %s", jarFile);
+            try {
+                JarReader reader = new JarReader(status, jarFile);
+                reader.stream().forEach(clazz -> new AnnotationVisitor(
+                        clazz, ANNOTATION_TYPE, status).visit());
+                reader.close();
+            } catch (IOException e) {
+                status.error(e);
+            }
+        }
+        if (status.ok()) {
+            System.exit(0);
+        } else {
+            System.exit(1);
+        }
+
+    }
+
+    private static void help(Options options) {
+        new HelpFormatter().printHelp(
+                "class2greylist path/to/classes.jar [classes2.jar ...]",
+                "Extracts greylist entries from classes jar files given",
+                options, null, true);
+        System.exit(1);
+    }
+}
diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java
new file mode 100644
index 0000000..f3a9d0b
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.class2greylist;
+
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.JavaClass;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Reads {@link JavaClass} members from a zip/jar file, providing a stream of them for processing.
+ * Any errors are reported via {@link Status#error(Throwable)}.
+ */
+public class JarReader {
+
+    private final Status mStatus;
+    private final String mFileName;
+    private final ZipFile mZipFile;
+
+    public JarReader(Status s, String filename) throws IOException {
+        mStatus = s;
+        mFileName = filename;
+        mZipFile = new ZipFile(mFileName);
+    }
+
+    private JavaClass openZipEntry(ZipEntry e) {
+        try {
+            mStatus.debug("Reading %s from %s", e.getName(), mFileName);
+            return new ClassParser(mZipFile.getInputStream(e), e.getName()).parse();
+        } catch (IOException ioe) {
+            mStatus.error(ioe);
+            return null;
+        }
+    }
+
+
+    public Stream<JavaClass> stream() {
+        return mZipFile.stream()
+                .filter(zipEntry -> zipEntry.getName().endsWith(".class"))
+                .map(zipEntry -> openZipEntry(zipEntry))
+                .filter(Objects::nonNull);
+    }
+
+    public void close() throws IOException {
+        mZipFile.close();
+    }
+}
diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java
new file mode 100644
index 0000000..d707898
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.class2greylist;
+
+import java.util.Locale;
+
+public class Status {
+
+    // Highlight "Error:" in red.
+    private static final String ERROR = "\u001B[31mError: \u001B[0m";
+
+    private final boolean mDebug;
+    private boolean mHasErrors;
+
+    public Status(boolean debug) {
+        mDebug = debug;
+    }
+
+    public void debug(String msg, Object... args) {
+        if (mDebug) {
+            System.err.println(String.format(Locale.US, msg, args));
+        }
+    }
+
+    public void error(Throwable t) {
+        System.err.print(ERROR);
+        t.printStackTrace(System.err);
+        mHasErrors = true;
+    }
+
+    public void error(String message) {
+        System.err.print(ERROR);
+        System.err.println(message);
+        mHasErrors = true;
+    }
+
+    public void greylistEntry(String signature) {
+        System.out.println(signature);
+    }
+
+    public boolean ok() {
+        return !mHasErrors;
+    }
+}
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/Android.mk b/tools/hiddenapi/class2greylist/test/Android.mk
similarity index 61%
rename from tools/aapt2/integration-tests/AutoNamespaceTest/Android.mk
rename to tools/hiddenapi/class2greylist/test/Android.mk
index 5d7a6f7..23f4156 100644
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/Android.mk
+++ b/tools/hiddenapi/class2greylist/test/Android.mk
@@ -1,4 +1,3 @@
-#
 # Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,7 +11,22 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-#
 
 LOCAL_PATH := $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+
+include $(CLEAR_VARS)
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := class2greylisttest
+
+LOCAL_STATIC_JAVA_LIBRARIES := class2greylistlib truth-host-prebuilt mockito-host junit-host
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := general-tests
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/layout/layout_two.xml b/tools/hiddenapi/class2greylist/test/AndroidTest.xml
similarity index 70%
rename from tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/layout/layout_two.xml
rename to tools/hiddenapi/class2greylist/test/AndroidTest.xml
index fb20220..66bb6344 100644
--- a/tools/aapt2/integration-tests/AutoNamespaceTest/LibTwo/res/layout/layout_two.xml
+++ b/tools/hiddenapi/class2greylist/test/AndroidTest.xml
@@ -13,6 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<View xmlns:custom="http://schemas.android.com/apk/res-auto"
-      custom:StaticLibOne_attr="@string/FooBar" />
+<configuration description="class2greylist tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="class2greylisttest.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java b/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java
new file mode 100644
index 0000000..2d97218
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.javac;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.android.class2greylist.Status;
+import com.android.class2greylist.AnnotationVisitor;
+
+import com.google.common.base.Joiner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.IOException;
+
+public class AnnotationVisitorTest {
+
+    private static final String ANNOTATION = "Lannotation/Anno;";
+
+    private Javac mJavac;
+    @Mock
+    private Status mStatus;
+
+    @Before
+    public void setup() throws IOException {
+        initMocks(this);
+        mJavac = new Javac();
+        mJavac.addSource("annotation.Anno", Joiner.on('\n').join(
+                "package annotation;",
+                 "import static java.lang.annotation.RetentionPolicy.CLASS;",
+                 "import java.lang.annotation.Retention;",
+                "import java.lang.annotation.Target;",
+                "@Retention(CLASS)",
+                "public @interface Anno {",
+                "  String expectedSignature() default \"\";",
+                "}"));
+    }
+
+    private void assertNoErrors() {
+        verify(mStatus, never()).error(any(Throwable.class));
+        verify(mStatus, never()).error(any(String.class));
+    }
+
+    @Test
+    public void testGreylistMethod() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  @Anno",
+                "  public void method() {}",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        assertNoErrors();
+        ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+        verify(mStatus, times(1)).greylistEntry(greylist.capture());
+        assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V");
+    }
+
+    @Test
+    public void testGreylistConstructor() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  @Anno",
+                "  public Class() {}",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        assertNoErrors();
+        ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+        verify(mStatus, times(1)).greylistEntry(greylist.capture());
+        assertThat(greylist.getValue()).isEqualTo("La/b/Class;-><init>()V");
+    }
+
+    @Test
+    public void testGreylistField() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  @Anno",
+                "  public int i;",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        assertNoErrors();
+        ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+        verify(mStatus, times(1)).greylistEntry(greylist.capture());
+        assertThat(greylist.getValue()).isEqualTo("La/b/Class;->i:I");
+    }
+
+    @Test
+    public void testGreylistMethodExpectedSignature() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  @Anno(expectedSignature=\"La/b/Class;->method()V\")",
+                "  public void method() {}",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        assertNoErrors();
+        ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+        verify(mStatus, times(1)).greylistEntry(greylist.capture());
+        assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V");
+    }
+
+    @Test
+    public void testGreylistMethodExpectedSignatureWrong() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  @Anno(expectedSignature=\"La/b/Class;->nomethod()V\")",
+                "  public void method() {}",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        verify(mStatus, times(1)).error(any(String.class));
+    }
+
+    @Test
+    public void testGreylistInnerClassMethod() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import annotation.Anno;",
+                "public class Class {",
+                "  public class Inner {",
+                "    @Anno",
+                "    public void method() {}",
+                "  }",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class$Inner"), ANNOTATION,
+                mStatus).visit();
+
+        assertNoErrors();
+        ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+        verify(mStatus, times(1)).greylistEntry(greylist.capture());
+        assertThat(greylist.getValue()).isEqualTo("La/b/Class$Inner;->method()V");
+    }
+
+    @Test
+    public void testMethodNotGreylisted() throws IOException {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "public class Class {",
+                "  public void method() {}",
+                "}"));
+        assertThat(mJavac.compile()).isTrue();
+
+        new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+                .visit();
+
+        assertNoErrors();
+        verify(mStatus, never()).greylistEntry(any(String.class));
+    }
+
+}
diff --git a/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java b/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java
new file mode 100644
index 0000000..202f412
--- /dev/null
+++ b/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.javac;
+
+import com.google.common.io.Files;
+
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.JavaClass;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+/**
+ * Helper class for compiling snippets of Java source and providing access to the resulting class
+ * files.
+ */
+public class Javac {
+
+    private final JavaCompiler mJavac;
+    private final StandardJavaFileManager mFileMan;
+    private final List<JavaFileObject> mCompilationUnits;
+    private final File mClassOutDir;
+
+    public Javac() throws IOException {
+        mJavac = ToolProvider.getSystemJavaCompiler();
+        mFileMan = mJavac.getStandardFileManager(null, Locale.US, null);
+        mClassOutDir = Files.createTempDir();
+        mFileMan.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(mClassOutDir));
+        mFileMan.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(mClassOutDir));
+        mCompilationUnits = new ArrayList<>();
+    }
+
+    private String classToFileName(String classname) {
+        return classname.replace('.', '/');
+    }
+
+    public Javac addSource(String classname, String contents) {
+        JavaFileObject java = new SimpleJavaFileObject(URI.create(
+                String.format("string:///%s.java", classToFileName(classname))),
+                JavaFileObject.Kind.SOURCE
+                ){
+            @Override
+            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+                return contents;
+            }
+        };
+        mCompilationUnits.add(java);
+        return this;
+    }
+
+    public boolean compile() {
+        JavaCompiler.CompilationTask task = mJavac.getTask(
+                null,
+                mFileMan,
+                null,
+                null,
+                null,
+                mCompilationUnits);
+        return task.call();
+    }
+
+    public InputStream getClassFile(String classname) throws IOException {
+        Iterable<? extends JavaFileObject> objs = mFileMan.getJavaFileObjects(
+                new File(mClassOutDir, String.format("%s.class", classToFileName(classname))));
+        if (!objs.iterator().hasNext()) {
+            return null;
+        }
+        return objs.iterator().next().openInputStream();
+    }
+
+    public JavaClass getCompiledClass(String classname) throws IOException {
+        return new ClassParser(getClassFile(classname),
+                String.format("%s.class", classToFileName(classname))).parse();
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6963ed0..922e025 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1585,13 +1585,12 @@
      * Return the record of {@link WifiActivityEnergyInfo} object that
      * has the activity and energy info. This can be used to ascertain what
      * the controller has been up to, since the last sample.
-     * @param updateType Type of info, cached vs refreshed.
      *
      * @return a record with {@link WifiActivityEnergyInfo} or null if
      * report is unavailable or unsupported
      * @hide
      */
-    public WifiActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
+    public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
         if (mService == null) return null;
         try {
             synchronized(this) {
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 928a1da..8fb7c87 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
@@ -721,6 +722,17 @@
     }
 
     /**
+     * Enable/Disable wifi scanning.
+     *
+     * {@hide}
+     */
+    @RequiresPermission(Manifest.permission.NETWORK_STACK)
+    public void setScanningEnabled(boolean enable) {
+        validateChannel();
+        mAsyncChannel.sendMessage(enable ? CMD_ENABLE : CMD_DISABLE);
+    }
+
+    /**
      * Register a listener that will receive results from all single scans
      * Either the onSuccess/onFailure will be called once when the listener is registered. After
      * (assuming onSuccess was called) all subsequent single scan results will be delivered to the
@@ -1164,6 +1176,10 @@
     public static final int CMD_DEREGISTER_SCAN_LISTENER    = BASE + 28;
     /** @hide */
     public static final int CMD_GET_SINGLE_SCAN_RESULTS     = BASE + 29;
+    /** @hide */
+    public static final int CMD_ENABLE                      = BASE + 30;
+    /** @hide */
+    public static final int CMD_DISABLE                     = BASE + 31;
 
     private Context mContext;
     private IWifiScanner mService;