Merge "Renamed BIND_DATA_SERVICE to BIND_TELEPHONY_DATA_SERVICE"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index bab2a85..231aaf2 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -232,7 +232,7 @@
         while (state.keepRunning()) {
             state.pauseTiming();
             final MeasuredText text = new MeasuredText.Builder(
-                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT)
                     .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                     .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                     .build();
diff --git a/api/current.txt b/api/current.txt
index 50579a4..c3e1ba0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11616,15 +11616,15 @@
 
   public final class AssetManager implements java.lang.AutoCloseable {
     method public void close();
-    method public final java.lang.String[] getLocales();
-    method public final java.lang.String[] list(java.lang.String) throws java.io.IOException;
-    method public final java.io.InputStream open(java.lang.String) throws java.io.IOException;
-    method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
-    method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
-    method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
-    method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
-    method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
-    method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
+    method public java.lang.String[] getLocales();
+    method public java.lang.String[] list(java.lang.String) throws java.io.IOException;
+    method public java.io.InputStream open(java.lang.String) throws java.io.IOException;
+    method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
+    method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
+    method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
+    method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
+    method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
+    method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
     field public static final int ACCESS_BUFFER = 3; // 0x3
     field public static final int ACCESS_RANDOM = 1; // 0x1
     field public static final int ACCESS_STREAMING = 2; // 0x2
@@ -16489,8 +16489,37 @@
 package android.hardware.fingerprint {
 
   public class FingerprintDialog {
-    method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
-    method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
+    method public void authenticate(android.hardware.fingerprint.FingerprintDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
+    method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
+    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+  }
+
+  public static abstract class FingerprintDialog.AuthenticationCallback {
+    ctor public FingerprintDialog.AuthenticationCallback();
+    method public void onAuthenticationError(int, java.lang.CharSequence);
+    method public void onAuthenticationFailed();
+    method public void onAuthenticationHelp(int, java.lang.CharSequence);
+    method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintDialog.AuthenticationResult);
+  }
+
+  public static class FingerprintDialog.AuthenticationResult {
+    method public android.hardware.fingerprint.FingerprintDialog.CryptoObject getCryptoObject();
   }
 
   public static class FingerprintDialog.Builder {
@@ -16502,10 +16531,19 @@
     method public android.hardware.fingerprint.FingerprintDialog.Builder setTitle(java.lang.CharSequence);
   }
 
-  public class FingerprintManager {
-    method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
-    method public boolean hasEnrolledFingerprints();
-    method public boolean isHardwareDetected();
+  public static final class FingerprintDialog.CryptoObject {
+    ctor public FingerprintDialog.CryptoObject(java.security.Signature);
+    ctor public FingerprintDialog.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintDialog.CryptoObject(javax.crypto.Mac);
+    method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
+    method public java.security.Signature getSignature();
+  }
+
+  public deprecated class FingerprintManager {
+    method public deprecated void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
+    method public deprecated boolean hasEnrolledFingerprints();
+    method public deprecated boolean isHardwareDetected();
     field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
     field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
     field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -16513,9 +16551,11 @@
     field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
     field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
     field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
     field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
     field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
     field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
     field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
     field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
     field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
@@ -24518,7 +24558,7 @@
     field public static final int DIRECTIONALITY_HYPER_CARDIOID = 4; // 0x4
     field public static final int DIRECTIONALITY_OMNI = 1; // 0x1
     field public static final int DIRECTIONALITY_SUPER_CARDIOID = 5; // 0x5
-    field public static final int DIRECTIONALITY_UNKNOW = 0; // 0x0
+    field public static final int DIRECTIONALITY_UNKNOWN = 0; // 0x0
     field public static final int LOCATION_MAINBODY = 1; // 0x1
     field public static final int LOCATION_MAINBODY_MOVABLE = 2; // 0x2
     field public static final int LOCATION_PERIPHERAL = 3; // 0x3
@@ -33075,7 +33115,7 @@
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
     field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
     field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
-    field public static final java.lang.String DISALLOW_CONFIG_LOCATION_MODE = "no_config_location_mode";
+    field public static final java.lang.String DISALLOW_CONFIG_LOCATION = "no_config_location";
     field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
     field public static final java.lang.String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
     field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
diff --git a/api/system-current.txt b/api/system-current.txt
index 4caa820..e06336b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -774,6 +774,7 @@
   public abstract class Context {
     method public boolean bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
     method public abstract android.content.Context createCredentialProtectedStorageContext();
+    method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.io.File getPreloadsFileCache();
     method public abstract boolean isCredentialProtectedStorage();
     method public abstract void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
@@ -2022,6 +2023,7 @@
     method public int describeContents();
     method public android.hardware.radio.RadioManager.BandDescriptor[] getBands();
     method public int getClassId();
+    method public java.util.Map<java.lang.String, java.lang.Integer> getDabFrequencyTable();
     method public int getId();
     method public java.lang.String getImplementor();
     method public int getNumAudioSources();
diff --git a/api/test-current.txt b/api/test-current.txt
index 92bf24d..b331ba0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1056,6 +1056,14 @@
 
 }
 
+package android.view.inputmethod {
+
+  public final class InputMethodManager {
+    method public boolean isInputMethodPickerShown();
+  }
+
+}
+
 package android.widget {
 
   public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4e41454..32da94f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -34,6 +34,7 @@
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
 #include <utils/String16.h>
+#include <statslog.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/system_properties.h>
@@ -235,6 +236,10 @@
         if (!args[0].compare(String8("write-to-disk"))) {
             return cmd_write_data_to_disk(out);
         }
+
+        if (!args[0].compare(String8("log-app-hook"))) {
+            return cmd_log_app_hook(out, args);
+        }
     }
 
     print_cmd_help(out);
@@ -272,6 +277,15 @@
     fprintf(out, "  Flushes all data on memory to disk.\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
+    fprintf(out, "  Writes an AppHook event to the statslog buffer.\n");
+    fprintf(out, "  UID           The uid to use. It is only possible to pass a UID\n");
+    fprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
+    fprintf(out, "                uid is used.\n");
+    fprintf(out, "  LABEL         Integer in [0, 15], as per atoms.proto.\n");
+    fprintf(out, "  STATE         Integer in [0, 3], as per atoms.proto.\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
     fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
     fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
     fprintf(out, "\n");
@@ -523,6 +537,42 @@
     return NO_ERROR;
 }
 
+status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+    bool good = false;
+    int32_t uid;
+    int32_t label;
+    int32_t state;
+    const int argCount = args.size();
+    if (argCount == 3) {
+        // Automatically pick the UID
+        uid = IPCThreadState::self()->getCallingUid();
+        label = atoi(args[1].c_str());
+        state = atoi(args[2].c_str());
+        good = true;
+    } else if (argCount == 4) {
+        uid = atoi(args[1].c_str());
+        // If it's a userdebug or eng build, then the shell user can impersonate other uids.
+        // Otherwise, the uid must match the actual caller's uid.
+        if (mEngBuild || (uid >= 0 && (uid_t)uid == IPCThreadState::self()->getCallingUid())) {
+            label = atoi(args[2].c_str());
+            state = atoi(args[3].c_str());
+            good = true;
+        } else {
+            fprintf(out,
+                    "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
+                            " or userdebug builds.\n");
+        }
+    }
+    if (good) {
+        fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
+        android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+    } else {
+        print_cmd_help(out);
+        return UNKNOWN_ERROR;
+    }
+    return NO_ERROR;
+}
+
 status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
     int s = atoi(args[1].c_str());
     vector<shared_ptr<LogEvent> > stats;
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fd3ed1d..109752b 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -183,6 +183,11 @@
     status_t cmd_write_data_to_disk(FILE* out);
 
     /**
+     * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+     */
+    status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+
+    /**
      * Print contents of a pulled metrics source.
      */
     status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b156d8d..ed570e7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -95,6 +95,8 @@
         AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
         ShutdownSequenceReported shutdown_sequence_reported = 56;
         BootSequenceReported boot_sequence_reported = 57;
+        DaveyOccurred davey_occurred = 58;
+        OverlayStateChanged overlay_state_changed = 59;
         // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 
@@ -723,6 +725,17 @@
 }
 
 /**
+ * Logs the duration of a davey (jank of >=700ms) when it occurs
+ *
+ * Logged from:
+ *   frameworks/base/libs/hwui/JankTracker.cpp
+ */
+message DaveyOccurred {
+    // Amount of time it took to render the frame. Should be >=700ms.
+    optional int64 jank_duration_ms = 1;
+}
+
+/**
  * Logs phone signal strength changes.
  *
  * Logged from:
@@ -967,6 +980,25 @@
 }
 
 /**
+ * Logs overlay action
+ * Logged from:
+ *     services/core/java/com/android/server/wm/Session.java
+ */
+message OverlayStateChanged {
+    optional int32 uid = 1;
+
+    optional string package_name = 2;
+
+    optional bool using_alert_window = 3;
+
+    enum State {
+        ENTERED = 1;
+        EXITED = 2;
+    }
+    optional State state = 4;
+}
+
+/**
  * Pulls bytes transferred via wifi (Sum of foreground and background usage).
  *
  * Pulled from:
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 9e72f5b..1dcd853 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -62,13 +62,14 @@
         const char* buffer;
         size_t len = android_log_write_list_buffer(mContext, &buffer);
         // turns to reader mode
-        mContext = create_android_log_parser(buffer, len);
-        init(mContext);
-        // destroy the context to save memory.
-        if (mContext) {
+        android_log_context contextForRead = create_android_log_parser(buffer, len);
+        if (contextForRead) {
+            init(contextForRead);
+            // destroy the context to save memory.
             // android_log_destroy will set mContext to NULL
-            android_log_destroy(&mContext);
+            android_log_destroy(&contextForRead);
         }
+        android_log_destroy(&mContext);
     }
 }
 
@@ -188,6 +189,9 @@
  * of the elements that are written to the log.
  */
 void LogEvent::init(android_log_context context) {
+    if (!context) {
+        return;
+    }
     android_log_list_element elem;
     // TODO: The log is actually structured inside one list.  This is convenient
     // because we'll be able to use it to put the attribution (WorkSource) block first
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index b6f440f..fae9172 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -129,43 +129,60 @@
         }
         bool matched = false;
         switch (matcher.value_matcher_case()) {
-            case FieldValueMatcher::ValueMatcherCase::kEqBool:
-                 // Logd does not support bool, it is int instead.
-                 matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kEqString:
-                 {
-                    if (IsAttributionUidField(*rootField)) {
-                        const int uid = ret.first->second.value_int();
-                        std::set<string> packageNames =
+            case FieldValueMatcher::ValueMatcherCase::kEqBool: {
+                // Logd does not support bool, it is int instead.
+                matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kEqString: {
+                if (IsAttributionUidField(*rootField)) {
+                    const int uid = ret.first->second.value_int();
+                    std::set<string> packageNames =
                             uidMap.getAppNamesFromUid(uid, true /* normalize*/);
-                        matched = packageNames.find(matcher.eq_string()) != packageNames.end();
-                    } else {
-                        matched = (ret.first->second.value_str() == matcher.eq_string());
-                    }
-                 }
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kEqInt:
-                 matched = (ret.first->second.value_int() == matcher.eq_int());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kLtInt:
-                 matched = (ret.first->second.value_int() < matcher.lt_int());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kGtInt:
-                 matched = (ret.first->second.value_int() > matcher.gt_int());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kLtFloat:
-                 matched = (ret.first->second.value_float() < matcher.lt_float());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kGtFloat:
-                 matched = (ret.first->second.value_float() > matcher.gt_float());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kLteInt:
-                 matched = (ret.first->second.value_int() <= matcher.lte_int());
-                 break;
-            case FieldValueMatcher::ValueMatcherCase::kGteInt:
-                 matched = (ret.first->second.value_int() >= matcher.gte_int());
-                 break;
+                    matched = packageNames.find(matcher.eq_string()) != packageNames.end();
+                } else {
+                    matched = (ret.first->second.value_str() == matcher.eq_string());
+                }
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kEqInt: {
+                    int64_t val = ret.first->second.has_value_int() ?
+                                  ret.first->second.value_int() : ret.first->second.value_long();
+                    matched = (val == matcher.eq_int());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kLtInt: {
+                int64_t val = ret.first->second.has_value_int() ?
+                              ret.first->second.value_int() : ret.first->second.value_long();
+                matched = (val < matcher.lt_int());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kGtInt: {
+                int64_t val = ret.first->second.has_value_int() ?
+                              ret.first->second.value_int() : ret.first->second.value_long();
+                matched = (val > matcher.gt_int());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
+                matched = (ret.first->second.value_float() < matcher.lt_float());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
+                matched = (ret.first->second.value_float() > matcher.gt_float());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kLteInt: {
+                int64_t val = ret.first->second.has_value_int() ?
+                              ret.first->second.value_int() : ret.first->second.value_long();
+                matched = (val <= matcher.lte_int());
+                break;
+            }
+            case FieldValueMatcher::ValueMatcherCase::kGteInt: {
+                int64_t val = ret.first->second.has_value_int() ?
+                              ret.first->second.value_int() : ret.first->second.value_long();
+                matched = (val >= matcher.gte_int());
+                break;
+            }
             default:
                 break;
         }
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d0737de..417145c 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -47,7 +47,7 @@
 
 MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
                                const long timeBaseSec, sp<UidMap> uidMap)
-    : mConfigKey(key), mUidMap(uidMap) {
+    : mConfigKey(key), mUidMap(uidMap), mStatsdUid(getStatsdUid()) {
     mConfigValid =
             initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
                              mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
@@ -61,6 +61,7 @@
 
         mAllowedUid.push_back(1000);
         mAllowedUid.push_back(0);
+        mAllowedUid.push_back(mStatsdUid);
         mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
     } else {
         for (const auto& source : config.allowed_log_source()) {
@@ -189,28 +190,47 @@
         return;
     }
 
-    if (event.GetTagId() != android::util::APP_HOOK) {
+    if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
+        // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+        status_t err = NO_ERROR;
+
+        // Uid is 3rd from last field and must match the caller's uid,
+        // unless that caller is statsd itself (statsd is allowed to spoof uids).
+        long appHookUid = event.GetLong(event.size()-2, &err);
+        int32_t loggerUid = event.GetUid();
+        if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != mStatsdUid)) {
+            VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid);
+            return;
+        }
+
+        // Label is 2nd from last field and must be from [0, 15].
+        long appHookLabel = event.GetLong(event.size()-1, &err);
+        if (err != NO_ERROR || appHookLabel < 0 || appHookLabel > 15) {
+            VLOG("AppHook does not have valid label %ld", appHookLabel);
+            return;
+        }
+
+        // The state must be from 0,3. This part of code must be manually updated.
+        long appHookState = event.GetLong(event.size(), &err);
+        if (err != NO_ERROR || appHookState < 0 || appHookState > 3) {
+            VLOG("AppHook does not have valid state %ld", appHookState);
+            return;
+        }
+    } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
+        // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
+        // Check that the davey duration is reasonable. Max length check is for privacy.
+        status_t err = NO_ERROR;
+        long duration = event.GetLong(event.size(), &err);
+        if (err != NO_ERROR || duration > 100000) {
+            VLOG("Davey duration is unreasonably long: %ld", duration);
+            return;
+        }
+    } else {
         std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
         if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
             VLOG("log source %d not on the whitelist", event.GetUid());
             return;
         }
-    } else { // Check that app hook fields are valid.
-        // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
-
-        // Label is 2nd from last field and must be from [0, 15].
-        status_t err = NO_ERROR;
-        long label = event.GetLong(event.size()-1, &err);
-        if (err != NO_ERROR || label < 0 || label > 15) {
-            VLOG("App hook does not have valid label %ld", label);
-            return;
-        }
-        // The state must be from 0,3. This part of code must be manually updated.
-        long apphookState = event.GetLong(event.size(), &err);
-        if (err != NO_ERROR || apphookState < 0 || apphookState > 3) {
-            VLOG("App hook does not have valid state %ld", apphookState);
-            return;
-        }
     }
 
     int tagId = event.GetTagId();
@@ -313,6 +333,16 @@
     return totalSize;
 }
 
+int32_t MetricsManager::getStatsdUid() {
+    auto suit = UidMap::sAidToUidMapping.find("AID_STATSD");
+    if (suit != UidMap::sAidToUidMapping.end()) {
+        return suit->second;
+    } else {
+        ALOGE("Statsd failed to find its own uid!");
+        return -1;
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d4b9102..a1220f9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -75,6 +75,9 @@
 
     sp<UidMap> mUidMap;
 
+    // The uid of statsd.
+    const int32_t mStatsdUid;
+
     bool mConfigValid = false;
 
     // The uid log sources from StatsdConfig.
@@ -136,6 +139,9 @@
 
     void initLogSourceWhiteList();
 
+    // Fetches the uid of statsd from UidMap.
+    static int32_t getStatsdUid();
+
     // The metrics that don't need to be uploaded or even reported.
     std::set<int64_t> mNoReportMetricIds;
 
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 2ea79a6..3eaf7a1 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -64,7 +64,7 @@
   oneof value_matcher {
     bool eq_bool = 3;
     string eq_string = 4;
-    int32 eq_int = 5;
+    int64 eq_int = 5;
 
     int64 lt_int = 6;
     int64 gt_int = 7;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 05e51a4..58936fc 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -15,6 +15,7 @@
 Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
 Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
 Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
+Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
 Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
 Landroid/app/ActivityManager$RunningAppProcessInfo;->processState:I
 Landroid/app/Activity;->mApplication:Landroid/app/Application;
@@ -24,6 +25,7 @@
 Landroid/app/Activity;->mToken:Landroid/os/IBinder;
 Landroid/app/Activity;->mWindow:Landroid/view/Window;
 Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
+Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
 Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/app/ActivityThread$ActivityClientRecord;->token:Landroid/os/IBinder;
 Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
@@ -31,6 +33,7 @@
 Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread;
 Landroid/app/ActivityThread;->currentApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->currentPackageName()Ljava/lang/String;
+Landroid/app/ActivityThread;->currentProcessName()Ljava/lang/String;
 Landroid/app/ActivityThread;->getApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;
 Landroid/app/ActivityThread;->getHandler()Landroid/os/Handler;
@@ -71,6 +74,9 @@
 Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
 Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
 Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
+Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
+Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;)I
+Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;I)I
 Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I
 Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I
 Landroid/app/AppOpsManager;->noteOp(I)I
@@ -182,18 +188,24 @@
 Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
 Landroid/content/pm/ApplicationInfo;->installLocation:I
 Landroid/content/pm/ApplicationInfo;->isForwardLocked()Z
+Landroid/content/pm/ApplicationInfo;->isInstantApp()Z
 Landroid/content/pm/ApplicationInfo;->isPrivilegedApp()Z
 Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->privateFlags:I
+Landroid/content/pm/ApplicationInfo;->targetSandboxVersion:I
 Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
 Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V
 Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
 Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
+Landroid/content/pm/PackageInstaller$SessionParams;->setGrantedRuntimePermissions([Ljava/lang/String;)V
+Landroid/content/pm/PackageInstaller$SessionParams;->setInstallAsInstantApp(Z)V
 Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V
 Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V
 Landroid/content/pm/PackageManager;->freeStorage(JLandroid/content/IntentSender;)V
 Landroid/content/pm/PackageManager;->freeStorage(Ljava/lang/String;JLandroid/content/IntentSender;)V
+Landroid/content/pm/PackageManager;->getApplicationInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo;
 Landroid/content/pm/PackageManager;->getPackageCandidateVolumes(Landroid/content/pm/ApplicationInfo;)Ljava/util/List;
+Landroid/content/pm/PackageManager;->getPackageInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
 Landroid/content/pm/PackageManager;->getPackageSizeInfo(Ljava/lang/String;Landroid/content/pm/IPackageStatsObserver;)V
 Landroid/content/pm/PackageManager;->getResourcesForApplicationAsUser(Ljava/lang/String;I)Landroid/content/res/Resources;
 Landroid/content/pm/PackageManager;->movePackage(Ljava/lang/String;Landroid/os/storage/VolumeInfo;)I
@@ -217,6 +229,7 @@
 Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I
 Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I
 Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I
+Landroid/content/res/AssetManager;->mObject:J
 Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
 Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream;
 Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream;
@@ -276,6 +289,7 @@
 Landroid/graphics/drawable/BitmapDrawable;->getTintMode()Landroid/graphics/PorterDuff$Mode;
 Landroid/graphics/drawable/BitmapDrawable;->setBitmap(Landroid/graphics/Bitmap;)V
 Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mConstantPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/DrawableContainer;->getOpticalInsets()Landroid/graphics/Insets;
 Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;
 Landroid/graphics/drawable/Drawable;->inflateWithAttributes(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/content/res/TypedArray;I)V
 Landroid/graphics/drawable/Drawable;->mCallback:Ljava/lang/ref/WeakReference;
@@ -358,9 +372,25 @@
 Landroid/net/ConnectivityManager;->mService:Landroid/net/IConnectivityManager;
 Landroid/net/ConnectivityManager;->requestRouteToHostAddress(ILjava/net/InetAddress;)Z
 Landroid/net/ConnectivityManager;->requestRouteToHost(II)Z
+Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
 Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V
 Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager;
+Landroid/net/NetworkStats;->capacity:I
+Landroid/net/NetworkStats;->defaultNetwork:[I
+Landroid/net/NetworkStats;->iface:[Ljava/lang/String;
+Landroid/net/NetworkStats;->metered:[I
+Landroid/net/NetworkStats;->operations:[J
+Landroid/net/NetworkStats;->roaming:[I
+Landroid/net/NetworkStats;->rxBytes:[J
+Landroid/net/NetworkStats;->rxPackets:[J
+Landroid/net/NetworkStats;->set:[I
+Landroid/net/NetworkStats;->size:I
+Landroid/net/NetworkStats;->tag:[I
+Landroid/net/NetworkStats;->txBytes:[J
+Landroid/net/NetworkStats;->txPackets:[J
+Landroid/net/NetworkStats;->uid:[I
 Landroid/net/SSLCertificateSocketFactory;->getHttpSocketFactory(ILandroid/net/SSLSessionCache;)Lorg/apache/http/conn/ssl/SSLSocketFactory;
+Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
 Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
 Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
 Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
@@ -534,7 +564,9 @@
 Landroid/os/UserManager;->getUserHandle(I)I
 Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
 Landroid/os/UserManager;->getUserSerialNumber(I)I
+Landroid/os/UserManager;->getUsers()Ljava/util/List;
 Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
+Landroid/os/UserManager;->isLinkedUser()Z
 Landroid/os/UserManager;->isUserUnlocked(I)Z
 Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
 Landroid/os/WorkSource;->add(I)Z
@@ -627,6 +659,7 @@
 Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
 Landroid/telephony/SubscriptionManager;->getSubId(I)[I
 Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
+Landroid/telephony/TelephonyManager;->checkCarrierPrivilegesForPackage(Ljava/lang/String;)I
 Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
 Landroid/telephony/TelephonyManager;->getCurrentPhoneType()I
 Landroid/telephony/TelephonyManager;->getCurrentPhoneType(I)I
@@ -636,10 +669,12 @@
 Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
 Landroid/telephony/TelephonyManager;->getLine1Number(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getNetworkClass(I)I
+Landroid/telephony/TelephonyManager;->getNetworkCountryIso(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getNetworkOperator(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getNetworkOperatorName(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getNetworkType(I)I
 Landroid/telephony/TelephonyManager;->getSimOperator(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSimOperatorName(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getSimSerialNumber(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getSubscriberId(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
@@ -711,6 +746,14 @@
 Landroid/view/SurfaceView;->mFormat:I
 Landroid/view/SurfaceView;->mRequestedFormat:I
 Landroid/view/SurfaceView;->mSurfaceHolder:Landroid/view/SurfaceHolder;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker;-><init>(Landroid/content/Context;I)V
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker;->logEvent(Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;)V
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(III)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(IIILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(II)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextSelection;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionStarted(I)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
 Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z
 Landroid/view/TextureView;->mLayer:Landroid/view/HardwareLayer;
 Landroid/view/TextureView;->mSurface:Landroid/graphics/SurfaceTexture;
@@ -718,6 +761,7 @@
 Landroid/view/TouchDelegate;->mDelegateTargeted:Z
 Landroid/view/VelocityTracker;->obtain(Ljava/lang/String;)Landroid/view/VelocityTracker;
 Landroid/view/View;->clearAccessibilityFocus()V
+Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z
 Landroid/view/View;->computeOpaqueFlags()V
 Landroid/view/ViewConfiguration;->mFadingMarqueeEnabled:Z
 Landroid/view/ViewConfiguration;->sHasPermanentMenuKeySet:Z
@@ -732,6 +776,7 @@
 Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl;
 Landroid/view/ViewGroup;->FLAG_SUPPORT_STATIC_TRANSFORMATIONS:I
 Landroid/view/ViewGroup;->FLAG_USE_CHILD_DRAWING_ORDER:I
+Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V
 Landroid/view/ViewGroup$MarginLayoutParams;->endMargin:I
 Landroid/view/ViewGroup$MarginLayoutParams;->startMargin:I
 Landroid/view/ViewGroup;->mChildren:[Landroid/view/View;
@@ -810,6 +855,7 @@
 Landroid/webkit/WebView;->enablePlatformNotifications()V
 Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebView;->getVisibleTitleHeight()I
 Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
 Landroid/webkit/WebView;->isPaused()Z
@@ -939,6 +985,7 @@
 Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable;
 Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable;
 Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V
+Landroid/widget/TextView;->assumeLayout()V
 Landroid/widget/TextView;->createEditorIfNeeded()V
 Landroid/widget/TextView;->mCursorDrawableRes:I
 Landroid/widget/TextView;->mCurTextColor:I
@@ -977,6 +1024,8 @@
 Lcom/android/internal/os/BatteryStatsImpl$Uid$Sensor;->getHandle()I
 Lcom/android/internal/os/BatteryStatsImpl$Uid$Sensor;->getSensorTime()Lcom/android/internal/os/BatteryStatsImpl$Timer;
 Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;->getWakeTime(I)Lcom/android/internal/os/BatteryStatsImpl$Timer;
+Lcom/android/internal/os/FuseAppLoop;->onCommand(IJJJI[B)V
+Lcom/android/internal/os/FuseAppLoop;->onOpen(JJ)[B
 Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;)D
 Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;I)D
 Lcom/android/internal/os/PowerProfile;->getBatteryCapacity()D
@@ -1038,8 +1087,13 @@
 Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
 Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I
 Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V
 Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
 Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
+Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
+Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
+Ldalvik/system/CloseGuard;->warnIfOpen()V
 Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
 Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
@@ -1050,6 +1104,7 @@
 Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
 Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
 Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
+Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
 Ldalvik/system/VMDebug;->dumpReferenceTables()V
 Ldalvik/system/VMRuntime;->clearGrowthLimit()V
 Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String;
@@ -1074,6 +1129,7 @@
 Ljava/lang/Class;->dexClassDefIndex:I
 Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader;
 Ljava/lang/Daemons$Daemon;->stop()V
+Ljava/lang/Daemons$Daemon;->thread:Ljava/lang/Thread;
 Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object;
 Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;
 Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon;
@@ -1092,6 +1148,8 @@
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
 Ljava/net/URI;->host:Ljava/lang/String;
 Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
+Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
+Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
 Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
 Ljava/util/ArrayList$SubList;->parentOffset:I
 Ljava/util/ArrayList$SubList;->size:I
@@ -1101,5 +1159,6 @@
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f21746c..39bccc3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -51,6 +51,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadSystemException;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -1329,11 +1330,7 @@
 
     private void copyStreamToWallpaperFile(InputStream data, FileOutputStream fos)
             throws IOException {
-        byte[] buffer = new byte[32768];
-        int amt;
-        while ((amt=data.read(buffer)) > 0) {
-            fos.write(buffer, 0, amt);
-        }
+        FileUtils.copy(data, fos);
     }
 
     /**
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 4461b16..38d9025 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -31,4 +31,7 @@
     SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
     int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
     void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
+
+    byte[] getBackupPayload(int user);
+    void applyRestore(in byte[] payload, int user);
 }
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index e5f3eae..3f13fff 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -20,9 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
+import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.IContentProvider;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
@@ -193,10 +193,15 @@
      * <p>
      * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
      * they still care about after a reboot.
+     * <p>
+     * This may only be called by apps that are the default launcher for the device
+     * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
      *
      * @param uri The uri of the slice being pinned.
      * @param specs The list of supported {@link SliceSpec}s of the callback.
      * @see SliceProvider#onSlicePinned(Uri)
+     * @see Intent#ACTION_ASSIST
+     * @see Intent#CATEGORY_HOME
      */
     public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
         try {
@@ -211,10 +216,15 @@
      * Remove a pin for a slice.
      * <p>
      * If the slice has no other pins/callbacks then the slice will be unpinned.
+     * <p>
+     * This may only be called by apps that are the default launcher for the device
+     * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
      *
      * @param uri The uri of the slice being unpinned.
      * @see #pinSlice
      * @see SliceProvider#onSliceUnpinned(Uri)
+     * @see Intent#ACTION_ASSIST
+     * @see Intent#CATEGORY_HOME
      */
     public void unpinSlice(@NonNull Uri uri) {
         try {
@@ -262,17 +272,13 @@
      */
     public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
         ContentResolver resolver = mContext.getContentResolver();
-        IContentProvider provider = resolver.acquireProvider(uri);
-        try {
+        try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
             Bundle extras = new Bundle();
             extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
-            final Bundle res = provider.call(resolver.getPackageName(),
-                    SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
+            final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
             return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to get slice descendants", e);
-        } finally {
-            resolver.releaseProvider(provider);
         }
         return Collections.emptyList();
     }
@@ -288,17 +294,15 @@
     public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
         Preconditions.checkNotNull(uri, "uri");
         ContentResolver resolver = mContext.getContentResolver();
-        IContentProvider provider = resolver.acquireProvider(uri);
-        if (provider == null) {
-            throw new IllegalArgumentException("Unknown URI " + uri);
-        }
-        try {
+        try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+            if (provider == null) {
+                throw new IllegalArgumentException("Unknown URI " + uri);
+            }
             Bundle extras = new Bundle();
             extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
             extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                     new ArrayList<>(supportedSpecs));
-            final Bundle res = provider.call(mContext.getPackageName(), SliceProvider.METHOD_SLICE,
-                    null, extras);
+            final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
             Bundle.setDefusable(res, true);
             if (res == null) {
                 return null;
@@ -308,8 +312,6 @@
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
             return null;
-        } finally {
-            resolver.releaseProvider(provider);
         }
     }
 
@@ -344,15 +346,13 @@
         String authority = providers.get(0).providerInfo.authority;
         Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(authority).build();
-        IContentProvider provider = resolver.acquireProvider(uri);
-        if (provider == null) {
-            throw new IllegalArgumentException("Unknown URI " + uri);
-        }
-        try {
+        try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+            if (provider == null) {
+                throw new IllegalArgumentException("Unknown URI " + uri);
+            }
             Bundle extras = new Bundle();
             extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
-            final Bundle res = provider.call(mContext.getPackageName(),
-                    SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
+            final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
             if (res == null) {
                 return null;
             }
@@ -361,8 +361,6 @@
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
             return null;
-        } finally {
-            resolver.releaseProvider(provider);
         }
     }
 
@@ -399,17 +397,15 @@
         String authority = providers.get(0).providerInfo.authority;
         Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(authority).build();
-        IContentProvider provider = resolver.acquireProvider(uri);
-        if (provider == null) {
-            throw new IllegalArgumentException("Unknown URI " + uri);
-        }
-        try {
+        try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+            if (provider == null) {
+                throw new IllegalArgumentException("Unknown URI " + uri);
+            }
             Bundle extras = new Bundle();
             extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
             extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                     new ArrayList<>(supportedSpecs));
-            final Bundle res = provider.call(mContext.getPackageName(),
-                    SliceProvider.METHOD_MAP_INTENT, null, extras);
+            final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
             if (res == null) {
                 return null;
             }
@@ -418,8 +414,6 @@
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
             return null;
-        } finally {
-            resolver.releaseProvider(provider);
         }
     }
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f2eb4a0..753f671 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -49,6 +49,7 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -4678,9 +4679,15 @@
      *
      * @hide
      */
-    public abstract Context createPackageContextAsUser(
+    @SystemApi
+    public Context createPackageContextAsUser(
             String packageName, @CreatePackageOptions int flags, UserHandle user)
-            throws PackageManager.NameNotFoundException;
+            throws PackageManager.NameNotFoundException {
+        if (Build.IS_ENG) {
+            throw new IllegalStateException("createPackageContextAsUser not overridden!");
+        }
+        return this;
+    }
 
     /**
      * Creates a context given an {@link android.content.pm.ApplicationInfo}.
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 0b16852..8fddb99 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -26,9 +26,12 @@
     void addClientProgress(float progress);
 
     String[] getNames();
+
     ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
     ParcelFileDescriptor openRead(String name);
 
+    void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
+
     void removeSplit(String splitName);
 
     void close();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df677d2..d0be6c8 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -829,7 +829,19 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+        }
 
+        /** {@hide} */
+        public void write(@NonNull String name, long offsetBytes, long lengthBytes,
+                @NonNull ParcelFileDescriptor fd) throws IOException {
+            try {
+                mSession.write(name, offsetBytes, lengthBytes, fd);
+            } catch (RuntimeException e) {
+                ExceptionUtils.maybeUnwrapIOException(e);
+                throw e;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         /**
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
new file mode 100644
index 0000000..c811999
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -0,0 +1,184 @@
+/*
+ * 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.hardware.biometrics;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.CancellationSignal;
+import android.os.Parcelable;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This is the common interface that all biometric authentication classes should implement.
+ * @hide
+ */
+public interface BiometricAuthenticator {
+
+    /**
+     * Container for biometric data
+     * @hide
+     */
+    abstract class BiometricIdentifier implements Parcelable {}
+
+    /**
+     * Container for callback data from {@link BiometricAuthenticator#authenticate(
+     * CancellationSignal, Executor, AuthenticationCallback)} and
+     * {@link BiometricAuthenticator#authenticate(CryptoObject, CancellationSignal, Executor,
+     * AuthenticationCallback)}
+     */
+    class AuthenticationResult {
+        private BiometricIdentifier mIdentifier;
+        private CryptoObject mCryptoObject;
+        private int mUserId;
+
+        /**
+         * @hide
+         */
+        public AuthenticationResult() { }
+
+        /**
+         * Authentication result
+         * @param crypto
+         * @param identifier
+         * @param userId
+         * @hide
+         */
+        public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+                int userId) {
+            mCryptoObject = crypto;
+            mIdentifier = identifier;
+            mUserId = userId;
+        }
+
+        /**
+         * Obtain the crypto object associated with this transaction
+         * @return crypto object provided to {@link BiometricAuthenticator#authenticate(
+         * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}
+         */
+        public CryptoObject getCryptoObject() {
+            return mCryptoObject;
+        }
+
+        /**
+         * Obtain the biometric identifier associated with this operation. Applications are strongly
+         * discouraged from associating specific identifiers with specific applications or
+         * operations.
+         * @hide
+         */
+        public BiometricIdentifier getId() {
+            return mIdentifier;
+        }
+
+        /**
+         * Obtain the userId for which this biometric was authenticated.
+         * @hide
+         */
+        public int getUserId() {
+            return mUserId;
+        }
+    };
+
+    /**
+     * Callback structure provided to {@link BiometricAuthenticator#authenticate(CancellationSignal,
+     * Executor, AuthenticationCallback)} or {@link BiometricAuthenticator#authenticate(
+     * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}. Users must provide
+     * an implementation of this for listening to biometric events.
+     */
+    abstract class AuthenticationCallback {
+        /**
+         * Called when an unrecoverable error has been encountered and the operation is complete.
+         * No further actions will be made on this object.
+         * @param errorCode An integer identifying the error message
+         * @param errString A human-readable error string that can be shown on an UI
+         */
+        public void onAuthenticationError(int errorCode, CharSequence errString) {}
+
+        /**
+         * Called when a recoverable error has been encountered during authentication. The help
+         * string is provided to give the user guidance for what went wrong, such as "Sensor dirty,
+         * please clean it."
+         * @param helpCode An integer identifying the error message
+         * @param helpString A human-readable string that can be shown on an UI
+         */
+        public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
+
+        /**
+         * Called when a biometric is recognized.
+         * @param result An object containing authentication-related data
+         */
+        public void onAuthenticationSucceeded(AuthenticationResult result) {}
+
+        /**
+         * Called when a biometric is valid but not recognized.
+         */
+        public void onAuthenticationFailed() {}
+
+        /**
+         * Called when a biometric has been acquired, but hasn't been processed yet.
+         * @hide
+         */
+        public void onAuthenticationAcquired(int acquireInfo) {}
+    };
+
+    /**
+     * This call warms up the hardware and starts scanning for valid biometrics. It terminates
+     * when {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
+     * AuthenticationResult)} is called, at which point the crypto object becomes invalid. This
+     * operation can be canceled by using the provided cancel object. The application wil receive
+     * authentication errors through {@link AuthenticationCallback}. Calling
+     * {@link BiometricAuthenticator#authenticate(CryptoObject, CancellationSignal, Executor,
+     * AuthenticationCallback)} while an existing authentication attempt is occurring will stop
+     * the previous client and start a new authentication. The interrupted client will receive a
+     * cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)}.
+     *
+     * @throws IllegalArgumentException If any of the arguments are null
+     *
+     * @param crypto Object associated with the call
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
+     */
+    void authenticate(@NonNull CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull AuthenticationCallback callback);
+
+    /**
+     * This call warms up the hardware and starts scanning for valid biometrics. It terminates
+     * when {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
+     * AuthenticationResult)} is called. This operation can be canceled by using the provided cancel
+     * object. The application wil receive authentication errors through
+     * {@link AuthenticationCallback}. Calling {@link BiometricAuthenticator#authenticate(
+     * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)} while an existing
+     * authentication attempt is occurring will stop the previous client and start a new
+     * authentication. The interrupted client will receive a cancelled notification through
+     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+     *
+     * @throws IllegalArgumentException If any of the arguments are null
+     *
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
+     */
+    void authenticate(@NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull AuthenticationCallback callback);
+}
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
new file mode 100644
index 0000000..638f525
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -0,0 +1,168 @@
+/*
+ * 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.hardware.biometrics;
+
+import android.hardware.fingerprint.FingerprintManager;
+
+/**
+ * Interface containing all of the fingerprint-specific constants.
+ * @hide
+ */
+public interface BiometricFingerprintConstants {
+    //
+    // Error messages from fingerprint hardware during initilization, enrollment, authentication or
+    // removal. Must agree with the list in fingerprint.h
+    //
+
+    /**
+     * The hardware is unavailable. Try again later.
+     */
+    public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+
+    /**
+     * Error state returned when the sensor was unable to process the current image.
+     */
+    public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
+
+    /**
+     * Error state returned when the current request has been running too long. This is intended to
+     * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
+     * platform and sensor-specific, but is generally on the order of 30 seconds.
+     */
+    public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+
+    /**
+     * Error state returned for operations like enrollment; the operation cannot be completed
+     * because there's not enough storage remaining to complete the operation.
+     */
+    public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+    /**
+     * The operation was canceled because the fingerprint sensor is unavailable. For example,
+     * this may happen when the user is switched, the device is locked or another pending operation
+     * prevents or disables it.
+     */
+    public static final int FINGERPRINT_ERROR_CANCELED = 5;
+
+    /**
+     * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
+     * provided fingerprint id was incorrect.
+     *
+     * @hide
+     */
+    public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
+
+    /**
+     * The operation was canceled because the API is locked out due to too many attempts.
+     * This occurs after 5 failed attempts, and lasts for 30 seconds.
+     */
+    public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
+
+    /**
+     * Hardware vendors may extend this list if there are conditions that do not fall under one of
+     * the above categories. Vendors are responsible for providing error strings for these errors.
+     * These messages are typically reserved for internal operations such as enrollment, but may be
+     * used to express vendor errors not covered by the ones in fingerprint.h. Applications are
+     * expected to show the error message string if they happen, but are advised not to rely on the
+     * message id since they will be device and vendor-specific
+     */
+    public static final int FINGERPRINT_ERROR_VENDOR = 8;
+
+    /**
+     * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
+     * Fingerprint authentication is disabled until the user unlocks with strong authentication
+     * (PIN/Pattern/Password)
+     */
+    public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
+
+    /**
+     * The user canceled the operation. Upon receiving this, applications should use alternate
+     * authentication (e.g. a password). The application should also provide the means to return
+     * to fingerprint authentication, such as a "use fingerprint" button.
+     */
+    public static final int FINGERPRINT_ERROR_USER_CANCELED = 10;
+
+    /**
+     * The user does not have any fingerprints enrolled.
+     */
+    public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11;
+
+    /**
+     * The device does not have a fingerprint sensor.
+     */
+    public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12;
+
+    /**
+     * @hide
+     */
+    public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
+
+    //
+    // Image acquisition messages. Must agree with those in fingerprint.h
+    //
+
+    /**
+     * The image acquired was good.
+     */
+    public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+
+    /**
+     * Only a partial fingerprint image was detected. During enrollment, the user should be
+     * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
+     */
+    public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
+
+    /**
+     * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
+     * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
+     */
+    public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
+
+    /**
+     * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
+     * For example, it's reasonable return this after multiple
+     * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
+     * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
+     * when this is returned.
+     */
+    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+
+    /**
+     * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
+     * linear array sensors that require a swipe motion.
+     */
+    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+
+    /**
+     * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
+     * linear array sensors,  this could also happen if the finger was moved during acquisition.
+     * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
+     * longer.
+     */
+    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+
+    /**
+     * Hardware vendors may extend this list if there are conditions that do not fall under one of
+     * the above categories. Vendors are responsible for providing error strings for these errors.
+     * @hide
+     */
+    public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
+    /**
+     * @hide
+     */
+    public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
+}
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
new file mode 100644
index 0000000..496d9c5
--- /dev/null
+++ b/core/java/android/hardware/biometrics/CryptoObject.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 android.hardware.biometrics;
+
+import android.annotation.NonNull;
+import android.security.keystore.AndroidKeyStoreProvider;
+
+import java.security.Signature;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
+/**
+ * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+ * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * @hide
+ */
+public class CryptoObject {
+    private final Object mCrypto;
+
+    public CryptoObject(@NonNull Signature signature) {
+        mCrypto = signature;
+    }
+
+    public CryptoObject(@NonNull Cipher cipher) {
+        mCrypto = cipher;
+    }
+
+    public CryptoObject(@NonNull Mac mac) {
+        mCrypto = mac;
+    }
+
+    /**
+     * Get {@link Signature} object.
+     * @return {@link Signature} object or null if this doesn't contain one.
+     */
+    public Signature getSignature() {
+        return mCrypto instanceof Signature ? (Signature) mCrypto : null;
+    }
+
+    /**
+     * Get {@link Cipher} object.
+     * @return {@link Cipher} object or null if this doesn't contain one.
+     */
+    public Cipher getCipher() {
+        return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
+    }
+
+    /**
+     * Get {@link Mac} object.
+     * @return {@link Mac} object or null if this doesn't contain one.
+     */
+    public Mac getMac() {
+        return mCrypto instanceof Mac ? (Mac) mCrypto : null;
+    }
+
+    /**
+     * @hide
+     * @return the opId associated with this object or 0 if none
+     */
+    public final long getOpId() {
+        return mCrypto != null
+                ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
+    }
+};
diff --git a/core/java/android/hardware/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
index c307634..c7ce8fa 100644
--- a/core/java/android/hardware/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.fingerprint;
 
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -22,7 +23,7 @@
  * Container for fingerprint metadata.
  * @hide
  */
-public final class Fingerprint implements Parcelable {
+public final class Fingerprint extends BiometricAuthenticator.BiometricIdentifier {
     private CharSequence mName;
     private int mGroupId;
     private int mFingerId;
diff --git a/core/java/android/hardware/fingerprint/FingerprintDialog.java b/core/java/android/hardware/fingerprint/FingerprintDialog.java
index 6b7fab7..49835963 100644
--- a/core/java/android/hardware/fingerprint/FingerprintDialog.java
+++ b/core/java/android/hardware/fingerprint/FingerprintDialog.java
@@ -23,19 +23,25 @@
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.CryptoObject;
 import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.text.TextUtils;
 
+import java.security.Signature;
 import java.util.concurrent.Executor;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
 /**
  * A class that manages a system-provided fingerprint dialog.
  */
-public class FingerprintDialog {
+public class FingerprintDialog implements BiometricAuthenticator, BiometricFingerprintConstants {
 
     /**
      * @hide
@@ -200,6 +206,7 @@
         }
     }
 
+    private PackageManager mPackageManager;
     private FingerprintManager mFingerprintManager;
     private Bundle mBundle;
     private ButtonInfo mPositiveButtonInfo;
@@ -227,37 +234,209 @@
         mPositiveButtonInfo = positiveButtonInfo;
         mNegativeButtonInfo = negativeButtonInfo;
         mFingerprintManager = context.getSystemService(FingerprintManager.class);
+        mPackageManager = context.getPackageManager();
     }
 
     /**
+     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+     * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+     */
+    public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
+        public CryptoObject(@NonNull Signature signature) {
+            super(signature);
+        }
+
+        public CryptoObject(@NonNull Cipher cipher) {
+            super(cipher);
+        }
+
+        public CryptoObject(@NonNull Mac mac) {
+            super(mac);
+        }
+
+        /**
+         * Get {@link Signature} object.
+         * @return {@link Signature} object or null if this doesn't contain one.
+         */
+        public Signature getSignature() {
+            return super.getSignature();
+        }
+
+        /**
+         * Get {@link Cipher} object.
+         * @return {@link Cipher} object or null if this doesn't contain one.
+         */
+        public Cipher getCipher() {
+            return super.getCipher();
+        }
+
+        /**
+         * Get {@link Mac} object.
+         * @return {@link Mac} object or null if this doesn't contain one.
+         */
+        public Mac getMac() {
+            return super.getMac();
+        }
+    }
+
+    /**
+     * Container for callback data from {@link #authenticate(
+     * CancellationSignal, Executor, AuthenticationCallback)} and
+     * {@link #authenticate(CryptoObject, CancellationSignal, Executor,
+     * AuthenticationCallback)}
+     */
+    public static class AuthenticationResult extends BiometricAuthenticator.AuthenticationResult {
+        /**
+         * Authentication result
+         * @param crypto
+         * @param identifier
+         * @param userId
+         * @hide
+         */
+        public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+                int userId) {
+            super(crypto, identifier, userId);
+        }
+        /**
+         * Obtain the crypto object associated with this transaction
+         * @return crypto object provided to {@link #authenticate(
+         * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}
+         */
+        public CryptoObject getCryptoObject() {
+            return (CryptoObject) super.getCryptoObject();
+        }
+    }
+
+    /**
+     * Callback structure provided to {@link FingerprintDialog#authenticate(CancellationSignal,
+     * Executor, AuthenticationCallback)} or {@link FingerprintDialog#authenticate(CryptoObject,
+     * CancellationSignal, Executor, AuthenticationCallback)}. Users must provide an implementation
+     * of this for listening to authentication events.
+     */
+    public static abstract class AuthenticationCallback extends
+            BiometricAuthenticator.AuthenticationCallback {
+        /**
+         * Called when an unrecoverable error has been encountered and the operation is complete.
+         * No further actions will be made on this object.
+         * @param errorCode An integer identifying the error message
+         * @param errString A human-readable error string that can be shown on an UI
+         */
+        @Override
+        public void onAuthenticationError(int errorCode, CharSequence errString) {}
+
+        /**
+         * Called when a recoverable error has been encountered during authentication. The help
+         * string is provided to give the user guidance for what went wrong, such as "Sensor dirty,
+         * please clean it."
+         * @param helpCode An integer identifying the error message
+         * @param helpString A human-readable string that can be shown on an UI
+         */
+        @Override
+        public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
+
+        /**
+         * Called when a biometric is recognized.
+         * @param result An object containing authentication-related data
+         */
+        public void onAuthenticationSucceeded(AuthenticationResult result) {}
+
+        /**
+         * Called when a biometric is valid but not recognized.
+         */
+        @Override
+        public void onAuthenticationFailed() {}
+
+        /**
+         * Called when a biometric has been acquired, but hasn't been processed yet.
+         * @hide
+         */
+        @Override
+        public void onAuthenticationAcquired(int acquireInfo) {}
+
+        /**
+         * @param result An object containing authentication-related data
+         * @hide
+         */
+        @Override
+        public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
+            onAuthenticationSucceeded(new AuthenticationResult(
+                    (CryptoObject) result.getCryptoObject(),
+                    result.getId(),
+                    result.getUserId()));
+        }
+    }
+
+
+    /**
+     * @param crypto Object associated with the call
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
+     * @hide
+     */
+    @Override
+    public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+        if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+            throw new IllegalArgumentException("Callback cannot be casted");
+        }
+        authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
+    }
+
+    /**
+     *
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
+     * @hide
+     */
+    @Override
+    public void authenticate(@NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+        if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+            throw new IllegalArgumentException("Callback cannot be casted");
+        }
+        authenticate(cancel, executor, (AuthenticationCallback) callback);
+    }
+
+
+    /**
      * This call warms up the fingerprint hardware, displays a system-provided dialog,
      * and starts scanning for a fingerprint. It terminates when
-     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
-     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
-     * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
-     * dismisses the system-provided dialog, at which point the crypto object becomes invalid.
-     * This operation can be canceled by using the provided cancel object. The application will
-     * receive authentication errors through {@link AuthenticationCallback}, and button events
-     * through the corresponding callback set in
-     * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
-     * It is safe to reuse the {@link FingerprintDialog} object, and calling
-     * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
-     * while an existing authentication attempt is occurring will stop the previous client and
-     * start a new authentication. The interrupted client will receive a cancelled notification
-     * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+     * {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)} is called, when
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(
+     * AuthenticationResult)}, or when the user dismisses the system-provided dialog, at which point
+     * the crypto object becomes invalid. This operation can be canceled by using the provided
+     * cancel object. The application will receive authentication errors through
+     * {@link AuthenticationCallback}, and button events through the
+     * corresponding callback set in {@link Builder#setNegativeButton(CharSequence,
+     * Executor, DialogInterface.OnClickListener)}. It is safe to reuse the
+     * {@link FingerprintDialog} object, and calling {@link FingerprintDialog#authenticate(
+     * CancellationSignal, Executor, AuthenticationCallback)} while an
+     * existing authentication attempt is occurring will stop the previous client and start a
+     * new authentication. The interrupted client will receive a cancelled notification through
+     * {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)}.
      *
-     * @throws IllegalArgumentException if any of the arguments are null
+     * @throws IllegalArgumentException If any of the arguments are null
      *
-     * @param crypto object associated with the call
-     * @param cancel an object that can be used to cancel authentication
-     * @param executor an executor to handle callback events
-     * @param callback an object to receive authentication events
+     * @param crypto Object associated with the call
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
      */
     @RequiresPermission(USE_FINGERPRINT)
-    public void authenticate(@NonNull FingerprintManager.CryptoObject crypto,
+    public void authenticate(@NonNull CryptoObject crypto,
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull FingerprintManager.AuthenticationCallback callback) {
+            @NonNull AuthenticationCallback callback) {
+        if (handlePreAuthenticationErrors(callback, executor)) {
+            return;
+        }
         mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,
                 callback);
     }
@@ -265,29 +444,57 @@
     /**
      * This call warms up the fingerprint hardware, displays a system-provided dialog,
      * and starts scanning for a fingerprint. It terminates when
-     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
-     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
-     * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
-     * dismisses the system-provided dialog. This operation can be canceled by using the provided
-     * cancel object. The application will receive authentication errors through
-     * {@link AuthenticationCallback}, and button events through the corresponding callback set in
+     * {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)} is called, when
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(
+     * AuthenticationResult)} is called, or when the user dismisses the system-provided dialog.
+     * This operation can be canceled by using the provided cancel object. The application will
+     * receive authentication errors through {@link AuthenticationCallback},
+     * and button events through the corresponding callback set in
      * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
      * It is safe to reuse the {@link FingerprintDialog} object, and calling
-     * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
-     * while an existing authentication attempt is occurring will stop the previous client and
-     * start a new authentication. The interrupted client will receive a cancelled notification
-     * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+     * {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
+     * AuthenticationCallback)} while an existing authentication attempt is
+     * occurring will stop the previous client and start a new authentication. The interrupted
+     * client will receive a cancelled notification through
+     * {@link AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)}.
      *
-     * @throws IllegalArgumentException if any of the arguments are null
+     * @throws IllegalArgumentException If any of the arguments are null
      *
-     * @param cancel an object that can be used to cancel authentication
-     * @param executor an executor to handle callback events
-     * @param callback an object to receive authentication events
+     * @param cancel An object that can be used to cancel authentication
+     * @param executor An executor to handle callback events
+     * @param callback An object to receive authentication events
      */
     @RequiresPermission(USE_FINGERPRINT)
     public void authenticate(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull FingerprintManager.AuthenticationCallback callback) {
+            @NonNull AuthenticationCallback callback) {
+        if (handlePreAuthenticationErrors(callback, executor)) {
+            return;
+        }
         mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);
     }
+
+    private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
+            Executor executor) {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            sendError(FINGERPRINT_ERROR_HW_NOT_PRESENT, callback, executor);
+            return true;
+        } else if (!mFingerprintManager.isHardwareDetected()) {
+            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, callback, executor);
+            return true;
+        } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
+            sendError(FINGERPRINT_ERROR_NO_FINGERPRINTS, callback, executor);
+            return true;
+        }
+        return false;
+    }
+
+    private void sendError(int error, AuthenticationCallback callback, Executor executor) {
+        executor.execute(() -> {
+            callback.onAuthenticationError(error, mFingerprintManager.getErrorString(
+                    error, 0 /* vendorCode */));
+        });
+    }
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 62d92c4..2dfe673 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -27,6 +27,8 @@
 import android.annotation.SystemService;
 import android.app.ActivityManager;
 import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -38,7 +40,6 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.util.Log;
 import android.util.Slog;
 
@@ -51,9 +52,14 @@
 
 /**
  * A class that coordinates access to the fingerprint hardware.
+ * @deprecated See {@link FingerprintDialog} which shows a system-provided dialog upon starting
+ * authentication. In a world where devices may have in-display fingerprint sensors, it's much
+ * more realistic to have a system-provided authentication dialog since the in-display sensor
+ * location may vary by vendor/device.
  */
+@Deprecated
 @SystemService(Context.FINGERPRINT_SERVICE)
-public class FingerprintManager {
+public class FingerprintManager implements BiometricFingerprintConstants {
     private static final String TAG = "FingerprintManager";
     private static final boolean DEBUG = true;
     private static final int MSG_ENROLL_RESULT = 100;
@@ -64,147 +70,14 @@
     private static final int MSG_REMOVED = 105;
     private static final int MSG_ENUMERATED = 106;
 
-    //
-    // Error messages from fingerprint hardware during initilization, enrollment, authentication or
-    // removal. Must agree with the list in fingerprint.h
-    //
-
-    /**
-     * The hardware is unavailable. Try again later.
-     */
-    public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
-
-    /**
-     * Error state returned when the sensor was unable to process the current image.
-     */
-    public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
-
-    /**
-     * Error state returned when the current request has been running too long. This is intended to
-     * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
-     * platform and sensor-specific, but is generally on the order of 30 seconds.
-     */
-    public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
-
-    /**
-     * Error state returned for operations like enrollment; the operation cannot be completed
-     * because there's not enough storage remaining to complete the operation.
-     */
-    public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
-
-    /**
-     * The operation was canceled because the fingerprint sensor is unavailable. For example,
-     * this may happen when the user is switched, the device is locked or another pending operation
-     * prevents or disables it.
-     */
-    public static final int FINGERPRINT_ERROR_CANCELED = 5;
-
-    /**
-     * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
-     * provided fingerprint id was incorrect.
-     *
-     * @hide
-     */
-    public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
-
-   /**
-     * The operation was canceled because the API is locked out due to too many attempts.
-     * This occurs after 5 failed attempts, and lasts for 30 seconds.
-     */
-    public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
-
-    /**
-     * Hardware vendors may extend this list if there are conditions that do not fall under one of
-     * the above categories. Vendors are responsible for providing error strings for these errors.
-     * These messages are typically reserved for internal operations such as enrollment, but may be
-     * used to express vendor errors not covered by the ones in fingerprint.h. Applications are
-     * expected to show the error message string if they happen, but are advised not to rely on the
-     * message id since they will be device and vendor-specific
-     */
-    public static final int FINGERPRINT_ERROR_VENDOR = 8;
-
-    /**
-     * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
-     * Fingerprint authentication is disabled until the user unlocks with strong authentication
-     * (PIN/Pattern/Password)
-     */
-    public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
-
-    /**
-     * The user canceled the operation. Upon receiving this, applications should use alternate
-     * authentication (e.g. a password). The application should also provide the means to return
-     * to fingerprint authentication, such as a "use fingerprint" button.
-     */
-    public static final int FINGERPRINT_ERROR_USER_CANCELED = 10;
-
-    /**
-     * @hide
-     */
-    public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
-
-    //
-    // Image acquisition messages. Must agree with those in fingerprint.h
-    //
-
-    /**
-     * The image acquired was good.
-     */
-    public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
-
-    /**
-     * Only a partial fingerprint image was detected. During enrollment, the user should be
-     * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
-     */
-    public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
-
-    /**
-     * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
-     * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
-     */
-    public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
-
-    /**
-     * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
-     * For example, it's reasonable return this after multiple
-     * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
-     * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
-     * when this is returned.
-     */
-    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
-
-    /**
-     * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
-     * linear array sensors that require a swipe motion.
-     */
-    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
-
-    /**
-     * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
-     * linear array sensors,  this could also happen if the finger was moved during acquisition.
-     * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
-     * longer.
-     */
-    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
-
-    /**
-     * Hardware vendors may extend this list if there are conditions that do not fall under one of
-     * the above categories. Vendors are responsible for providing error strings for these errors.
-     * @hide
-     */
-    public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
-    /**
-     * @hide
-     */
-    public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
-
     private IFingerprintService mService;
     private Context mContext;
     private IBinder mToken = new Binder();
-    private AuthenticationCallback mAuthenticationCallback;
+    private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
     private EnrollmentCallback mEnrollmentCallback;
     private RemovalCallback mRemovalCallback;
     private EnumerateCallback mEnumerateCallback;
-    private CryptoObject mCryptoObject;
+    private android.hardware.biometrics.CryptoObject mCryptoObject;
     private Fingerprint mRemovalFingerprint;
     private Handler mHandler;
     private Executor mExecutor;
@@ -217,9 +90,9 @@
     }
 
     private class OnAuthenticationCancelListener implements OnCancelListener {
-        private CryptoObject mCrypto;
+        private android.hardware.biometrics.CryptoObject mCrypto;
 
-        public OnAuthenticationCancelListener(CryptoObject crypto) {
+        public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
             mCrypto = crypto;
         }
 
@@ -233,18 +106,17 @@
      * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
      */
-    public static final class CryptoObject {
-
+    public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
         public CryptoObject(@NonNull Signature signature) {
-            mCrypto = signature;
+            super(signature);
         }
 
         public CryptoObject(@NonNull Cipher cipher) {
-            mCrypto = cipher;
+            super(cipher);
         }
 
         public CryptoObject(@NonNull Mac mac) {
-            mCrypto = mac;
+            super(mac);
         }
 
         /**
@@ -252,7 +124,7 @@
          * @return {@link Signature} object or null if this doesn't contain one.
          */
         public Signature getSignature() {
-            return mCrypto instanceof Signature ? (Signature) mCrypto : null;
+            return super.getSignature();
         }
 
         /**
@@ -260,7 +132,7 @@
          * @return {@link Cipher} object or null if this doesn't contain one.
          */
         public Cipher getCipher() {
-            return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
+            return super.getCipher();
         }
 
         /**
@@ -268,20 +140,9 @@
          * @return {@link Mac} object or null if this doesn't contain one.
          */
         public Mac getMac() {
-            return mCrypto instanceof Mac ? (Mac) mCrypto : null;
+            return super.getMac();
         }
-
-        /**
-         * @hide
-         * @return the opId associated with this object or 0 if none
-         */
-        public long getOpId() {
-            return mCrypto != null ?
-                    AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
-        }
-
-        private final Object mCrypto;
-    };
+    }
 
     /**
      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
@@ -334,13 +195,15 @@
      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
      * fingerprint events.
      */
-    public static abstract class AuthenticationCallback {
+    public static abstract class AuthenticationCallback
+            extends BiometricAuthenticator.AuthenticationCallback {
         /**
          * Called when an unrecoverable error has been encountered and the operation is complete.
          * No further callbacks will be made on this object.
          * @param errorCode An integer identifying the error message
          * @param errString A human-readable error string that can be shown in UI
          */
+        @Override
         public void onAuthenticationError(int errorCode, CharSequence errString) { }
 
         /**
@@ -350,6 +213,7 @@
          * @param helpCode An integer identifying the error message
          * @param helpString A human-readable string that can be shown in UI
          */
+        @Override
         public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
 
         /**
@@ -361,6 +225,7 @@
         /**
          * Called when a fingerprint is valid but not recognized.
          */
+        @Override
         public void onAuthenticationFailed() { }
 
         /**
@@ -369,7 +234,19 @@
          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
          * @hide
          */
+        @Override
         public void onAuthenticationAcquired(int acquireInfo) {}
+
+        /**
+         * @hide
+         * @param result
+         */
+        @Override
+        public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
+            onAuthenticationSucceeded(new AuthenticationResult(
+                    (CryptoObject) result.getCryptoObject(),
+                    (Fingerprint) result.getId(), result.getUserId()));
+        }
     };
 
     /**
@@ -489,7 +366,12 @@
      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
      *         facility</a>.
      * @throws IllegalStateException if the crypto primitive is not initialized.
+     * @deprecated See {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
+     * FingerprintDialog.AuthenticationCallback)} and {@link FingerprintDialog#authenticate(
+     * FingerprintDialog.CryptoObject, CancellationSignal, Executor,
+     * FingerprintDialog.AuthenticationCallback)}
      */
+    @Deprecated
     @RequiresPermission(USE_FINGERPRINT)
     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
@@ -554,12 +436,12 @@
      * @param userId the user ID that the fingerprint hardware will authenticate for.
      */
     private void authenticate(int userId,
-            @Nullable CryptoObject crypto,
+            @Nullable android.hardware.biometrics.CryptoObject crypto,
             @NonNull CancellationSignal cancel,
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull IFingerprintDialogReceiver receiver,
-            @NonNull AuthenticationCallback callback) {
+            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         mCryptoObject = crypto;
         if (cancel.isCanceled()) {
             Log.w(TAG, "authentication already canceled");
@@ -598,7 +480,7 @@
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull IFingerprintDialogReceiver receiver,
-            @NonNull AuthenticationCallback callback) {
+            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         if (cancel == null) {
             throw new IllegalArgumentException("Must supply a cancellation signal");
         }
@@ -626,12 +508,12 @@
      * @param callback
      * @hide
      */
-    public void authenticate(@NonNull CryptoObject crypto,
+    public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
             @NonNull CancellationSignal cancel,
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull IFingerprintDialogReceiver receiver,
-            @NonNull AuthenticationCallback callback) {
+            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         if (crypto == null) {
             throw new IllegalArgumentException("Must supply a crypto object");
         }
@@ -648,9 +530,10 @@
             throw new IllegalArgumentException("Must supply a receiver");
         }
         if (callback == null) {
-            throw new IllegalArgumentException("Must supply a calback");
+            throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticate(UserHandle.myUserId(), crypto, cancel, bundle, executor, receiver, callback);
+        authenticate(UserHandle.myUserId(), crypto, cancel,
+                bundle, executor, receiver, callback);
     }
 
     /**
@@ -848,7 +731,10 @@
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
+     * @deprecated See {@link FingerprintDialog} and
+     * {@link FingerprintDialog#FINGERPRINT_ERROR_NO_FINGERPRINTS}
      */
+    @Deprecated
     @RequiresPermission(USE_FINGERPRINT)
     public boolean hasEnrolledFingerprints() {
         if (mService != null) try {
@@ -879,7 +765,10 @@
      * Determine if fingerprint hardware is present and functional.
      *
      * @return true if hardware is present and functional, false otherwise.
+     * @deprecated See {@link FingerprintDialog} and
+     * {@link FingerprintDialog#FINGERPRINT_ERROR_HW_UNAVAILABLE}
      */
+    @Deprecated
     @RequiresPermission(USE_FINGERPRINT)
     public boolean isHardwareDetected() {
         if (mService != null) {
@@ -1049,8 +938,8 @@
 
     private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
         if (mAuthenticationCallback != null) {
-            final AuthenticationResult result =
-                    new AuthenticationResult(mCryptoObject, fp, userId);
+            final BiometricAuthenticator.AuthenticationResult result =
+                    new BiometricAuthenticator.AuthenticationResult(mCryptoObject, fp, userId);
             mAuthenticationCallback.onAuthenticationSucceeded(result);
         }
     }
@@ -1126,7 +1015,7 @@
         }
     }
 
-    private void cancelAuthentication(CryptoObject cryptoObject) {
+    private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
         if (mService != null) try {
             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
         } catch (RemoteException e) {
@@ -1160,6 +1049,12 @@
             case FINGERPRINT_ERROR_USER_CANCELED:
                 return mContext.getString(
                         com.android.internal.R.string.fingerprint_error_user_canceled);
+            case FINGERPRINT_ERROR_NO_FINGERPRINTS:
+                return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_no_fingerprints);
+            case FINGERPRINT_ERROR_HW_NOT_PRESENT:
+                return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_hw_not_present);
             case FINGERPRINT_ERROR_VENDOR: {
                     String[] msgArray = mContext.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_error_vendor);
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index b00f603..e1d7edf 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -213,6 +213,7 @@
         private final boolean mIsBgScanSupported;
         private final Set<Integer> mSupportedProgramTypes;
         private final Set<Integer> mSupportedIdentifierTypes;
+        @Nullable private final Map<String, Integer> mDabFrequencyTable;
         @NonNull private final Map<String, String> mVendorInfo;
 
         /** @hide */
@@ -221,6 +222,7 @@
                 boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
                 @ProgramSelector.ProgramType int[] supportedProgramTypes,
                 @ProgramSelector.IdentifierType int[] supportedIdentifierTypes,
+                @Nullable Map<String, Integer> dabFrequencyTable,
                 Map<String, String> vendorInfo) {
             mId = id;
             mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
@@ -236,6 +238,13 @@
             mIsBgScanSupported = isBgScanSupported;
             mSupportedProgramTypes = arrayToSet(supportedProgramTypes);
             mSupportedIdentifierTypes = arrayToSet(supportedIdentifierTypes);
+            if (dabFrequencyTable != null) {
+                for (Map.Entry<String, Integer> entry : dabFrequencyTable.entrySet()) {
+                    Objects.requireNonNull(entry.getKey());
+                    Objects.requireNonNull(entry.getValue());
+                }
+            }
+            mDabFrequencyTable = dabFrequencyTable;
             mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
         }
 
@@ -363,6 +372,19 @@
         }
 
         /**
+         * A frequency table for Digital Audio Broadcasting (DAB).
+         *
+         * The key is a channel name, i.e. 5A, 7B.
+         *
+         * The value is a frequency, in kHz.
+         *
+         * @return a frequency table, or {@code null} if the module doesn't support DAB
+         */
+        public @Nullable Map<String, Integer> getDabFrequencyTable() {
+            return mDabFrequencyTable;
+        }
+
+        /**
          * A map of vendor-specific opaque strings, passed from HAL without changes.
          * Format of these strings can vary across vendors.
          *
@@ -403,6 +425,7 @@
             mIsBgScanSupported = in.readInt() == 1;
             mSupportedProgramTypes = arrayToSet(in.createIntArray());
             mSupportedIdentifierTypes = arrayToSet(in.createIntArray());
+            mDabFrequencyTable = Utils.readStringIntMap(in);
             mVendorInfo = Utils.readStringMap(in);
         }
 
@@ -433,6 +456,7 @@
             dest.writeInt(mIsBgScanSupported ? 1 : 0);
             dest.writeIntArray(setToArray(mSupportedProgramTypes));
             dest.writeIntArray(setToArray(mSupportedIdentifierTypes));
+            Utils.writeStringIntMap(dest, mDabFrequencyTable);
             Utils.writeStringMap(dest, mVendorInfo);
         }
 
@@ -456,67 +480,31 @@
 
         @Override
         public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + mId;
-            result = prime * result + mServiceName.hashCode();
-            result = prime * result + mClassId;
-            result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
-            result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
-            result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
-            result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
-            result = prime * result + mNumTuners;
-            result = prime * result + mNumAudioSources;
-            result = prime * result + (mIsCaptureSupported ? 1 : 0);
-            result = prime * result + Arrays.hashCode(mBands);
-            result = prime * result + (mIsBgScanSupported ? 1 : 0);
-            result = prime * result + mVendorInfo.hashCode();
-            return result;
+            return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion,
+                mSerial, mNumTuners, mNumAudioSources, mIsCaptureSupported, mBands,
+                mIsBgScanSupported, mDabFrequencyTable, mVendorInfo);
         }
 
         @Override
         public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (!(obj instanceof ModuleProperties))
-                return false;
+            if (this == obj) return true;
+            if (!(obj instanceof ModuleProperties)) return false;
             ModuleProperties other = (ModuleProperties) obj;
-            if (mId != other.getId())
-                return false;
+
+            if (mId != other.getId()) return false;
             if (!TextUtils.equals(mServiceName, other.mServiceName)) return false;
-            if (mClassId != other.getClassId())
-                return false;
-            if (mImplementor == null) {
-                if (other.getImplementor() != null)
-                    return false;
-            } else if (!mImplementor.equals(other.getImplementor()))
-                return false;
-            if (mProduct == null) {
-                if (other.getProduct() != null)
-                    return false;
-            } else if (!mProduct.equals(other.getProduct()))
-                return false;
-            if (mVersion == null) {
-                if (other.getVersion() != null)
-                    return false;
-            } else if (!mVersion.equals(other.getVersion()))
-                return false;
-            if (mSerial == null) {
-                if (other.getSerial() != null)
-                    return false;
-            } else if (!mSerial.equals(other.getSerial()))
-                return false;
-            if (mNumTuners != other.getNumTuners())
-                return false;
-            if (mNumAudioSources != other.getNumAudioSources())
-                return false;
-            if (mIsCaptureSupported != other.isCaptureSupported())
-                return false;
-            if (!Arrays.equals(mBands, other.getBands()))
-                return false;
-            if (mIsBgScanSupported != other.isBackgroundScanningSupported())
-                return false;
-            if (!mVendorInfo.equals(other.mVendorInfo)) return false;
+            if (mClassId != other.mClassId) return false;
+            if (!Objects.equals(mImplementor, other.mImplementor)) return false;
+            if (!Objects.equals(mProduct, other.mProduct)) return false;
+            if (!Objects.equals(mVersion, other.mVersion)) return false;
+            if (!Objects.equals(mSerial, other.mSerial)) return false;
+            if (mNumTuners != other.mNumTuners) return false;
+            if (mNumAudioSources != other.mNumAudioSources) return false;
+            if (mIsCaptureSupported != other.mIsCaptureSupported) return false;
+            if (!Objects.equals(mBands, other.mBands)) return false;
+            if (mIsBgScanSupported != other.mIsBgScanSupported) return false;
+            if (!Objects.equals(mDabFrequencyTable, other.mDabFrequencyTable)) return false;
+            if (!Objects.equals(mVendorInfo, other.mVendorInfo)) return false;
             return true;
         }
     }
diff --git a/core/java/android/hardware/radio/Utils.java b/core/java/android/hardware/radio/Utils.java
index f1b5897..9887f78 100644
--- a/core/java/android/hardware/radio/Utils.java
+++ b/core/java/android/hardware/radio/Utils.java
@@ -56,6 +56,29 @@
         return map;
     }
 
+    static void writeStringIntMap(@NonNull Parcel dest, @Nullable Map<String, Integer> map) {
+        if (map == null) {
+            dest.writeInt(0);
+            return;
+        }
+        dest.writeInt(map.size());
+        for (Map.Entry<String, Integer> entry : map.entrySet()) {
+            dest.writeString(entry.getKey());
+            dest.writeInt(entry.getValue());
+        }
+    }
+
+    static @NonNull Map<String, Integer> readStringIntMap(@NonNull Parcel in) {
+        int size = in.readInt();
+        Map<String, Integer> map = new HashMap<>();
+        while (size-- > 0) {
+            String key = in.readString();
+            int value = in.readInt();
+            map.put(key, value);
+        }
+        return map;
+    }
+
     static <T extends Parcelable> void writeSet(@NonNull Parcel dest, @Nullable Set<T> set) {
         if (set == null) {
             dest.writeInt(0);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index bda720bb..7922276 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -439,6 +439,10 @@
         }
     }
 
+    private static long addIfSupported(long stat) {
+        return (stat == UNSUPPORTED) ? 0 : stat;
+    }
+
     /**
      * Return number of packets transmitted across mobile networks since device
      * boot. Counts packets across all mobile network interfaces, and always
@@ -451,7 +455,7 @@
     public static long getMobileTxPackets() {
         long total = 0;
         for (String iface : getMobileIfaces()) {
-            total += getTxPackets(iface);
+            total += addIfSupported(getTxPackets(iface));
         }
         return total;
     }
@@ -468,7 +472,7 @@
     public static long getMobileRxPackets() {
         long total = 0;
         for (String iface : getMobileIfaces()) {
-            total += getRxPackets(iface);
+            total += addIfSupported(getRxPackets(iface));
         }
         return total;
     }
@@ -485,7 +489,7 @@
     public static long getMobileTxBytes() {
         long total = 0;
         for (String iface : getMobileIfaces()) {
-            total += getTxBytes(iface);
+            total += addIfSupported(getTxBytes(iface));
         }
         return total;
     }
@@ -502,7 +506,7 @@
     public static long getMobileRxBytes() {
         long total = 0;
         for (String iface : getMobileIfaces()) {
-            total += getRxBytes(iface);
+            total += addIfSupported(getRxBytes(iface));
         }
         return total;
     }
@@ -517,9 +521,7 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
-            if (stat != UNSUPPORTED) {
-                total += stat;
-            }
+            total += addIfSupported(stat);
         }
         return total;
     }
@@ -534,9 +536,7 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
-            if (stat != UNSUPPORTED) {
-                total += stat;
-            }
+            total += addIfSupported(stat);
         }
         return total;
     }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 9edcc0e..5ca3a41 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -720,6 +720,10 @@
                 LOOP: while (end < length) {
                     switch (uriString.charAt(end)) {
                         case '/': // Start of path
+                        case '\\':// Start of path
+                          // Per http://url.spec.whatwg.org/#host-state, the \ character
+                          // is treated as if it were a / character when encountered in a
+                          // host
                         case '?': // Start of query
                         case '#': // Start of fragment
                             break LOOP;
@@ -758,6 +762,10 @@
                         case '#': // Start of fragment
                             return ""; // Empty path.
                         case '/': // Start of path!
+                        case '\\':// Start of path!
+                          // Per http://url.spec.whatwg.org/#host-state, the \ character
+                          // is treated as if it were a / character when encountered in a
+                          // host
                             break LOOP;
                     }
                     pathStart++;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 21d245d..1160415c 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -33,6 +33,7 @@
 import android.webkit.MimeTypeMap;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.SizedInputStream;
 
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
@@ -93,7 +94,7 @@
 
     private static final long COPY_CHECKPOINT_BYTES = 524288;
 
-    public interface CopyListener {
+    public interface ProgressListener {
         public void onProgress(long progress);
     }
 
@@ -202,7 +203,7 @@
     }
 
     /**
-     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+     * @deprecated use {@link #copy(File, File)} instead.
      */
     @Deprecated
     public static boolean copyFile(File srcFile, File destFile) {
@@ -215,7 +216,7 @@
     }
 
     /**
-     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+     * @deprecated use {@link #copy(File, File)} instead.
      */
     @Deprecated
     public static void copyFileOrThrow(File srcFile, File destFile) throws IOException {
@@ -255,44 +256,124 @@
         }
     }
 
-    public static void copy(File from, File to) throws IOException {
+    /**
+     * Copy the contents of one file to another, replacing any existing content.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull File from, @NonNull File to) throws IOException {
+        return copy(from, to, null, null);
+    }
+
+    /**
+     * Copy the contents of one file to another, replacing any existing content.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @param listener to be periodically notified as the copy progresses.
+     * @param signal to signal if the copy should be cancelled early.
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull File from, @NonNull File to,
+            @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+            throws IOException {
         try (FileInputStream in = new FileInputStream(from);
                 FileOutputStream out = new FileOutputStream(to)) {
-            copy(in, out);
+            return copy(in, out, listener, signal);
         }
     }
 
-    public static void copy(InputStream in, OutputStream out) throws IOException {
-        copy(in, out, null, null);
+    /**
+     * Copy the contents of one stream to another.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
+        return copy(in, out, null, null);
     }
 
-    public static void copy(InputStream in, OutputStream out, CopyListener listener,
-            CancellationSignal signal) throws IOException {
+    /**
+     * Copy the contents of one stream to another.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @param listener to be periodically notified as the copy progresses.
+     * @param signal to signal if the copy should be cancelled early.
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull InputStream in, @NonNull OutputStream out,
+            @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+            throws IOException {
         if (ENABLE_COPY_OPTIMIZATIONS) {
             if (in instanceof FileInputStream && out instanceof FileOutputStream) {
-                copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
+                return copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
                         listener, signal);
             }
         }
 
         // Worse case fallback to userspace
-        copyInternalUserspace(in, out, listener, signal);
+        return copyInternalUserspace(in, out, listener, signal);
     }
 
-    public static void copy(FileDescriptor in, FileDescriptor out) throws IOException {
-        copy(in, out, null, null);
+    /**
+     * Copy the contents of one FD to another.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out)
+            throws IOException {
+        return copy(in, out, null, null);
     }
 
-    public static void copy(FileDescriptor in, FileDescriptor out, CopyListener listener,
-            CancellationSignal signal) throws IOException {
+    /**
+     * Copy the contents of one FD to another.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @param listener to be periodically notified as the copy progresses.
+     * @param signal to signal if the copy should be cancelled early.
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+            throws IOException {
+        return copy(in, out, listener, signal, Long.MAX_VALUE);
+    }
+
+    /**
+     * Copy the contents of one FD to another.
+     * <p>
+     * Attempts to use several optimization strategies to copy the data in the
+     * kernel before falling back to a userspace copy as a last resort.
+     *
+     * @param listener to be periodically notified as the copy progresses.
+     * @param signal to signal if the copy should be cancelled early.
+     * @param count the number of bytes to copy.
+     * @return number of bytes copied.
+     */
+    public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            @Nullable ProgressListener listener, @Nullable CancellationSignal signal, long count)
+            throws IOException {
         if (ENABLE_COPY_OPTIMIZATIONS) {
             try {
                 final StructStat st_in = Os.fstat(in);
                 final StructStat st_out = Os.fstat(out);
                 if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) {
-                    copyInternalSendfile(in, out, listener, signal);
+                    return copyInternalSendfile(in, out, listener, signal, count);
                 } else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {
-                    copyInternalSplice(in, out, listener, signal);
+                    return copyInternalSplice(in, out, listener, signal, count);
                 }
             } catch (ErrnoException e) {
                 throw e.rethrowAsIOException();
@@ -300,23 +381,25 @@
         }
 
         // Worse case fallback to userspace
-        copyInternalUserspace(in, out, listener, signal);
+        return copyInternalUserspace(in, out, listener, signal, count);
     }
 
     /**
      * Requires one of input or output to be a pipe.
      */
     @VisibleForTesting
-    public static void copyInternalSplice(FileDescriptor in, FileDescriptor out,
-            CopyListener listener, CancellationSignal signal) throws ErrnoException {
+    public static long copyInternalSplice(FileDescriptor in, FileDescriptor out,
+            ProgressListener listener, CancellationSignal signal, long count)
+            throws ErrnoException {
         long progress = 0;
         long checkpoint = 0;
 
         long t;
-        while ((t = Os.splice(in, null, out, null, COPY_CHECKPOINT_BYTES,
+        while ((t = Os.splice(in, null, out, null, Math.min(count, COPY_CHECKPOINT_BYTES),
                 SPLICE_F_MOVE | SPLICE_F_MORE)) != 0) {
             progress += t;
             checkpoint += t;
+            count -= t;
 
             if (checkpoint >= COPY_CHECKPOINT_BYTES) {
                 if (signal != null) {
@@ -328,21 +411,24 @@
                 checkpoint = 0;
             }
         }
+        return progress;
     }
 
     /**
      * Requires both input and output to be a regular file.
      */
     @VisibleForTesting
-    public static void copyInternalSendfile(FileDescriptor in, FileDescriptor out,
-            CopyListener listener, CancellationSignal signal) throws ErrnoException {
+    public static long copyInternalSendfile(FileDescriptor in, FileDescriptor out,
+            ProgressListener listener, CancellationSignal signal, long count)
+            throws ErrnoException {
         long progress = 0;
         long checkpoint = 0;
 
         long t;
-        while ((t = Os.sendfile(out, in, null, COPY_CHECKPOINT_BYTES)) != 0) {
+        while ((t = Os.sendfile(out, in, null, Math.min(count, COPY_CHECKPOINT_BYTES))) != 0) {
             progress += t;
             checkpoint += t;
+            count -= t;
 
             if (checkpoint >= COPY_CHECKPOINT_BYTES) {
                 if (signal != null) {
@@ -354,17 +440,24 @@
                 checkpoint = 0;
             }
         }
+        return progress;
     }
 
     @VisibleForTesting
-    public static void copyInternalUserspace(FileDescriptor in, FileDescriptor out,
-            CopyListener listener, CancellationSignal signal) throws IOException {
-        copyInternalUserspace(new FileInputStream(in), new FileOutputStream(out), listener, signal);
+    public static long copyInternalUserspace(FileDescriptor in, FileDescriptor out,
+            ProgressListener listener, CancellationSignal signal, long count) throws IOException {
+        if (count != Long.MAX_VALUE) {
+            return copyInternalUserspace(new SizedInputStream(new FileInputStream(in), count),
+                    new FileOutputStream(out), listener, signal);
+        } else {
+            return copyInternalUserspace(new FileInputStream(in),
+                    new FileOutputStream(out), listener, signal);
+        }
     }
 
     @VisibleForTesting
-    public static void copyInternalUserspace(InputStream in, OutputStream out,
-            CopyListener listener, CancellationSignal signal) throws IOException {
+    public static long copyInternalUserspace(InputStream in, OutputStream out,
+            ProgressListener listener, CancellationSignal signal) throws IOException {
         long progress = 0;
         long checkpoint = 0;
         byte[] buffer = new byte[8192];
@@ -386,6 +479,7 @@
                 checkpoint = 0;
             }
         }
+        return progress;
     }
 
     /**
@@ -997,7 +1091,7 @@
                     }
                 }
             } catch (IOException | ErrnoException e) {
-                throw new RuntimeException(e);
+                // Ignored
             } finally {
                 if (sink) {
                     SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b2b43cf..2093cec 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -393,8 +393,9 @@
     public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
 
     /**
-     * Specifies if a user is disallowed from configuring location mode. Device owner and profile
-     * owners can set this restriction and it only applies on the managed user.
+     * Specifies if a user is disallowed from enabling or disabling location providers. As a
+     * result, user is disallowed from turning on or off location. Device owner and profile owners
+     * can set this restriction and it only applies on the managed user.
      *
      * <p>In a managed profile, location sharing is forced off when it's off on primary user, so
      * user can still turn off location sharing on managed profile when the restriction is set by
@@ -408,11 +409,12 @@
      *
      * <p>Key for user restrictions.
      * <p>Type: Boolean
+     * @see android.location.LocationManager#isProviderEnabled(String)
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
-    public static final String DISALLOW_CONFIG_LOCATION_MODE = "no_config_location_mode";
+    public static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
 
     /**
      * Specifies if date, time and timezone configuring is disallowed.
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index 747400d..a5f9305 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -21,6 +21,8 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.CancellationSignal.OnCancelListener;
+import android.os.FileUtils;
+import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
@@ -114,28 +116,15 @@
 
         @Override
         protected Void doInBackground(Void... params) {
-            InputStream in = null;
-            OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
-            final byte[] buffer = new byte[8192];
-            try {
-                in = new FileInputStream(mFile);
-                while (true) {
-                    if (isCancelled()) {
-                        break;
-                    }
-                    final int readByteCount = in.read(buffer);
-                    if (readByteCount < 0) {
-                        break;
-                    }
-                    out.write(buffer, 0, readByteCount);
-                }
-             } catch (IOException ioe) {
-                 Log.e(LOG_TAG, "Error writing data!", ioe);
-                 mResultCallback.onWriteFailed(mContext.getString(
-                         R.string.write_fail_reason_cannot_write));
-             } finally {
-                IoUtils.closeQuietly(in);
-                IoUtils.closeQuietly(out);
+            try (InputStream in = new FileInputStream(mFile);
+                    OutputStream out = new FileOutputStream(mDestination.getFileDescriptor())) {
+                FileUtils.copy(in, out, null, mCancellationSignal);
+            } catch (OperationCanceledException e) {
+                // Ignored; already handled below
+            } catch (IOException e) {
+                Log.e(LOG_TAG, "Error writing data!", e);
+                mResultCallback.onWriteFailed(mContext.getString(
+                        R.string.write_fail_reason_cannot_write));
             }
             return null;
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ad0ce49..e3b8a109 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9315,17 +9315,6 @@
         private static final Validator WIFI_WAKEUP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
-         * Value to specify if Wi-Fi Wakeup is available.
-         *
-         * Wi-Fi Wakeup will only operate if it's available
-         * and {@link #WIFI_WAKEUP_ENABLED} is true.
-         *
-         * Type: int (0 for false, 1 for true)
-         * @hide
-         */
-        public static final String WIFI_WAKEUP_AVAILABLE = "wifi_wakeup_available";
-
-        /**
          * Value to specify whether network quality scores and badging should be shown in the UI.
          *
          * Type: int (0 for false, 1 for true)
@@ -10750,14 +10739,14 @@
         public static final String LOW_POWER_MODE = "low_power";
 
         /**
-         * Battery level [1-99] at which low power mode automatically turns on.
+         * Battery level [1-100] at which low power mode automatically turns on.
          * If 0, it will not automatically turn on.
          * @hide
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
 
         private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
-                new SettingsValidators.InclusiveIntegerRangeValidator(0, 99);
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
 
          /**
          * If not 0, the activity manager will aggressively finish activities and
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index f0b9fa2d..65ce67f 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import java.io.IOException;
@@ -168,8 +169,10 @@
                     throw new IOException("Error in communicating with Secure Element");
                 }
                 return response;
-            } catch (RemoteException e) {
+            } catch (ServiceSpecificException e) {
                 throw new IOException(e.getMessage());
+            } catch (RemoteException e) {
+                throw new IllegalStateException(e.getMessage());
             }
         }
     }
@@ -244,8 +247,10 @@
             synchronized (mLock) {
                 return mChannel.selectNext();
             }
-        } catch (RemoteException e) {
+        } catch (ServiceSpecificException e) {
             throw new IOException(e.getMessage());
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e.getMessage());
         }
     }
 }
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 9f15739..3dec976 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -24,6 +24,7 @@
 
 import android.annotation.NonNull;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import java.io.IOException;
@@ -45,8 +46,7 @@
     private final Object mLock = new Object();
 
 
-    Reader(SEService service, String name, ISecureElementReader reader) throws
-            IOException {
+    Reader(SEService service, String name, ISecureElementReader reader) {
         if (reader == null || service == null || name == null) {
             throw new IllegalArgumentException("Parameters cannot be null");
         }
@@ -96,8 +96,10 @@
             ISecureElementSession session;
             try {
                 session = mReader.openSession();
-            } catch (RemoteException e) {
+            } catch (ServiceSpecificException e) {
                 throw new IOException(e.getMessage());
+            } catch (RemoteException e) {
+                throw new IllegalStateException(e.getMessage());
             }
             if (session == null) {
                 throw new IOException("service session is null.");
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 1e37277d..b8937e6 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -42,6 +42,23 @@
  */
 public class SEService {
 
+    /**
+     * Error code used with ServiceSpecificException.
+     * Thrown if there was an error communicating with the Secure Element.
+     *
+     * @hide
+     */
+    public static final int IO_ERROR = 1;
+
+    /**
+     * Error code used with ServiceSpecificException.
+     * Thrown if AID cannot be selected or is not available when opening
+     * a logical channel.
+     *
+     * @hide
+     */
+    public static final int NO_SUCH_ELEMENT_ERROR = 2;
+
     private static final String TAG = "OMAPI.SEService";
 
     private final Object mLock = new Object();
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index bb2a032..19a018e 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import java.io.IOException;
@@ -207,8 +208,16 @@
                     return null;
                 }
                 return new Channel(mService, this, channel);
+            } catch (ServiceSpecificException e) {
+                if (e.errorCode == SEService.IO_ERROR) {
+                    throw new IOException(e.getMessage());
+                } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
+                    throw new NoSuchElementException(e.getMessage());
+                } else {
+                    throw new IllegalStateException(e.getMessage());
+                }
             } catch (RemoteException e) {
-                throw new IOException(e.getMessage());
+                throw new IllegalStateException(e.getMessage());
             }
         }
     }
@@ -311,8 +320,16 @@
                     return null;
                 }
                 return new Channel(mService, this, channel);
+            } catch (ServiceSpecificException e) {
+                if (e.errorCode == SEService.IO_ERROR) {
+                    throw new IOException(e.getMessage());
+                } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
+                    throw new NoSuchElementException(e.getMessage());
+                } else {
+                    throw new IllegalStateException(e.getMessage());
+                }
             } catch (RemoteException e) {
-                throw new IOException(e.getMessage());
+                throw new IllegalStateException(e.getMessage());
             }
         }
     }
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 4e4a037..7cd08f7 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -26,9 +26,13 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.security.KeyStore;
+import android.security.keystore.AndroidKeyStoreProvider;
 
 import com.android.internal.widget.ILockSettings;
 
+import java.security.Key;
+import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.List;
@@ -113,9 +117,11 @@
 
 
     private final ILockSettings mBinder;
+    private final KeyStore mKeyStore;
 
-    private RecoveryController(ILockSettings binder) {
+    private RecoveryController(ILockSettings binder, KeyStore keystore) {
         mBinder = binder;
+        mKeyStore = keystore;
     }
 
     /**
@@ -133,7 +139,7 @@
     public static RecoveryController getInstance(Context context) {
         ILockSettings lockSettings =
                 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
-        return new RecoveryController(lockSettings);
+        return new RecoveryController(lockSettings, KeyStore.getInstance());
     }
 
     /**
@@ -430,6 +436,7 @@
     }
 
     /**
+     * Deprecated.
      * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
      * key store. Returns the raw material of the key.
      *
@@ -444,7 +451,6 @@
     public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
             throws InternalRecoveryServiceException, LockScreenRequiredException {
         try {
-            // TODO: add account
             return mBinder.generateAndStoreKey(alias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -457,6 +463,72 @@
     }
 
     /**
+     * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
+     * key store. Returns {@link javax.crypto.SecretKey}.
+     *
+     * @param alias The key alias.
+     * @param account The account associated with the key.
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
+     *     to generate recoverable keys, as the snapshots are encrypted using a key derived from the
+     *     lock screen.
+     * @hide
+     */
+    public Key generateKey(@NonNull String alias, byte[] account)
+            throws InternalRecoveryServiceException, LockScreenRequiredException {
+        // TODO: update RecoverySession.recoverKeys
+        try {
+            String grantAlias = mBinder.generateKey(alias, account);
+            if (grantAlias == null) {
+                return null;
+            }
+            Key result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+                    mKeyStore,
+                    grantAlias,
+                    KeyStore.UID_SELF);
+            return result;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (UnrecoverableKeyException e) {
+            throw new InternalRecoveryServiceException("Access to newly generated key failed for");
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ERROR_INSECURE_USER) {
+                throw new LockScreenRequiredException(e.getMessage());
+            }
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Gets a key called {@code alias} from the recoverable key store.
+     *
+     * @param alias The key alias.
+     * @return The key.
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     * @throws UnrecoverableKeyException if key is permanently invalidated or not found.
+     * @hide
+     */
+    public @Nullable Key getKey(@NonNull String alias)
+            throws InternalRecoveryServiceException, UnrecoverableKeyException {
+        try {
+            String grantAlias = mBinder.getKey(alias);
+            if (grantAlias == null) {
+                return null;
+            }
+            return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+                    mKeyStore,
+                    grantAlias,
+                    KeyStore.UID_SELF);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
      * Removes a key called {@code alias} from the recoverable key store.
      *
      * @param alias The key alias.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 23ae4b9..d66322c 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -17,6 +17,7 @@
 package android.service.notification;
 
 import android.app.ActivityManager;
+import android.app.AlarmManager;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.content.ComponentName;
@@ -1445,4 +1446,99 @@
         return !config.allowAlarms  && !config.allowMediaSystemOther
                 && areAllPriorityOnlyNotificationZenSoundsMuted(config);
     }
+
+    /**
+     * Returns a description of the current do not disturb settings from config.
+     * - If turned on manually and end time is known, returns end time.
+     * - If turned on by an automatic rule, returns the automatic rule name.
+     * - If on due to an app, returns the app name.
+     * - If there's a combination of rules/apps that trigger, then shows the one that will
+     *  last the longest if applicable.
+     * @return null if do not disturb is off.
+     */
+    public static String getDescription(Context context, boolean zenOn, ZenModeConfig config) {
+        if (!zenOn) {
+            return null;
+        }
+
+        String secondaryText = "";
+        long latestEndTime = -1;
+
+        // DND turned on by manual rule
+        if (config.manualRule != null) {
+            final Uri id = config.manualRule.conditionId;
+            if (config.manualRule.enabler != null) {
+                // app triggered manual rule
+                String appName = getOwnerCaption(context, config.manualRule.enabler);
+                if (!appName.isEmpty()) {
+                    secondaryText = appName;
+                }
+            } else {
+                if (id == null) {
+                    // Do not disturb manually triggered to remain on forever until turned off
+                    // No subtext
+                    return null;
+                } else {
+                    latestEndTime = tryParseCountdownConditionId(id);
+                    if (latestEndTime > 0) {
+                        final CharSequence formattedTime = getFormattedTime(context,
+                                latestEndTime, isToday(latestEndTime),
+                                context.getUserId());
+                        secondaryText = context.getString(R.string.zen_mode_until, formattedTime);
+                    }
+                }
+            }
+        }
+
+        // DND turned on by an automatic rule
+        for (ZenRule automaticRule : config.automaticRules.values()) {
+            if (automaticRule.isAutomaticActive()) {
+                if (isValidEventConditionId(automaticRule.conditionId)
+                        || isValidScheduleConditionId(automaticRule.conditionId)) {
+                    // set text if automatic rule end time is the latest active rule end time
+                    long endTime = parseAutomaticRuleEndTime(context, automaticRule.conditionId);
+                    if (endTime > latestEndTime) {
+                        latestEndTime = endTime;
+                        secondaryText = automaticRule.name;
+                    }
+                } else {
+                    // set text if 3rd party rule
+                    return automaticRule.name;
+                }
+            }
+        }
+
+        return !secondaryText.equals("") ? secondaryText : null;
+    }
+
+    private static long parseAutomaticRuleEndTime(Context context, Uri id) {
+        if (isValidEventConditionId(id)) {
+            // cannot look up end times for events
+            return Long.MAX_VALUE;
+        }
+
+        if (isValidScheduleConditionId(id)) {
+            ScheduleCalendar schedule = toScheduleCalendar(id);
+            long endTimeMs = schedule.getNextChangeTime(System.currentTimeMillis());
+
+            // check if automatic rule will end on next alarm
+            if (schedule.exitAtAlarm()) {
+                long nextAlarm = getNextAlarm(context);
+                schedule.maybeSetNextAlarm(System.currentTimeMillis(), nextAlarm);
+                if (schedule.shouldExitForAlarm(endTimeMs)) {
+                    return nextAlarm;
+                }
+            }
+
+            return endTimeMs;
+        }
+
+        return -1;
+    }
+
+    private static long getNextAlarm(Context context) {
+        final AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        final AlarmManager.AlarmClockInfo info = alarms.getNextAlarmClock(context.getUserId());
+        return info != null ? info.getTriggerTime() : 0;
+    }
 }
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 4c6e511..a3eeb27 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -106,18 +106,22 @@
         calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
 
         MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
-        md.update(DEFAULT_SALT);
-        md.update(verityBlock);
+        md.update(header);
+        md.update(extensions);
         md.update(apkDigest);
         return md.digest();
     }
 
+    /**
+     * Internal method to generate various parts of FSVerity constructs, including the header,
+     * extensions, Merkle tree, and the tree's root hash.  The output buffer is flipped to the
+     * generated data size and is readey for consuming.
+     */
     private static void calculateFsveritySignatureInternal(
             RandomAccessFile apk, SignatureInfo signatureInfo, ByteBuffer treeOutput,
             ByteBuffer rootHashOutput, ByteBuffer headerOutput, ByteBuffer extensionsOutput)
             throws IOException, NoSuchAlgorithmException, DigestException {
         assertSigningBlockAlignedAndHasFullPages(signatureInfo);
-
         long signingBlockSize =
                 signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
         long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
@@ -128,6 +132,7 @@
                     levelOffset, treeOutput);
             if (rootHashOutput != null) {
                 rootHashOutput.put(apkRootHash);
+                rootHashOutput.flip();
             }
         }
 
@@ -333,9 +338,9 @@
         buffer.put((byte) 0);               // auth block offset, disabled here
         buffer.put((byte) 2);               // extension count
         buffer.put(salt);                   // salt (8 bytes)
-        // skip(buffer, 22);                // reserved
+        skip(buffer, 22);                   // reserved
 
-        buffer.rewind();
+        buffer.flip();
         return buffer;
     }
 
@@ -396,12 +401,10 @@
             buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE);  // length
             skip(buffer, 7);                                            // reserved
             buffer.putInt(Math.toIntExact(signingBlockOffset));         // databytes
-
-            // There are extra kPadding bytes of 0s here, included in the total size field of the
-            // extension header. The output ByteBuffer is assumed to be initialized to 0.
+            skip(buffer, kPadding);                                     // padding
         }
 
-        buffer.rewind();
+        buffer.flip();
         return buffer;
     }
 
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 3fd4696..8cb46b7 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -23,6 +23,10 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -396,6 +400,33 @@
         return true;
     }
 
+    /**
+     *  Get the Bitmap from the Drawable.
+     *
+     *  If the Bitmap needed to be scaled up to account for density, BitmapDrawable
+     *  handles this at draw time. But this class doesn't actually draw the Bitmap;
+     *  it is just a holder for native code to access its SkBitmap. So this needs to
+     *  get a version that is scaled to account for density.
+     */
+    private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) {
+        Bitmap bitmap = bitmapDrawable.getBitmap();
+        final int scaledWidth  = bitmapDrawable.getIntrinsicWidth();
+        final int scaledHeight = bitmapDrawable.getIntrinsicHeight();
+        if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) {
+            return bitmap;
+        }
+
+        Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        RectF dst = new RectF(0, 0, scaledWidth, scaledHeight);
+
+        Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig());
+        Canvas canvas = new Canvas(scaled);
+        Paint paint = new Paint();
+        paint.setFilterBitmap(true);
+        canvas.drawBitmap(bitmap, src, dst, paint);
+        return scaled;
+    }
+
     private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
         final XmlResourceParser parser = resources.getXml(resourceId);
         final int bitmapRes;
@@ -452,7 +483,8 @@
                                 + "is different. All frames should have the exact same size and "
                                 + "share the same hotspot.");
                     }
-                    mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
+                    BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
+                    mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
                 }
             }
         }
@@ -461,7 +493,8 @@
                     + "refer to a bitmap drawable.");
         }
 
-        final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+        final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
         validateHotSpot(bitmap, hotSpotX, hotSpotY);
         // Set the properties now that we have successfully loaded the icon.
         mBitmap = bitmap;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3cbd275..c3e9e73 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23689,9 +23689,16 @@
         Point shadowTouchPoint = new Point();
         shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
 
-        if ((shadowSize.x <= 0) || (shadowSize.y <= 0)
+        if ((shadowSize.x < 0) || (shadowSize.y < 0)
                 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
-            throw new IllegalStateException("Drag shadow dimensions must be positive");
+            throw new IllegalStateException("Drag shadow dimensions must not be negative");
+        }
+
+        // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder
+        // does not accept zero size surface.
+        if (shadowSize.x == 0  || shadowSize.y == 0) {
+            shadowSize.x = 1;
+            shadowSize.y = 1;
         }
 
         if (ViewDebug.DEBUG_DRAG) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7db5c32..33c9f7a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
@@ -2137,6 +2138,26 @@
     }
 
     /**
+     * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected.
+     *
+     * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure
+     * that this test API returns when and only while and only while
+     * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not
+     * pass CTS.</p>
+     *
+     * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI.
+     * @hide
+     */
+    @TestApi
+    public boolean isInputMethodPickerShown() {
+        try {
+            return mService.isInputMethodPickerShownForTest();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Show the settings for enabling subtypes of the specified input method.
      * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
      * subtypes of all input methods will be shown.
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 1dc5b44..4b951fa 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -23,10 +23,12 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
@@ -53,7 +55,6 @@
 import com.android.internal.R;
 
 import java.io.IOException;
-import java.io.InputStream;
 
 /**
  * Displays image resources, for example {@link android.graphics.Bitmap}
@@ -946,21 +947,15 @@
             }
         } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
                 || ContentResolver.SCHEME_FILE.equals(scheme)) {
-            InputStream stream = null;
             try {
-                stream = mContext.getContentResolver().openInputStream(uri);
-                return Drawable.createFromResourceStream(sCompatUseCorrectStreamDensity
-                        ? getResources() : null, null, stream, null);
-            } catch (Exception e) {
+                Resources res = sCompatUseCorrectStreamDensity ? getResources() : null;
+                ImageDecoder.Source src = ImageDecoder.createSource(mContext.getContentResolver(),
+                        uri, res);
+                return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
+            } catch (IOException e) {
                 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
-            } finally {
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                        Log.w(LOG_TAG, "Unable to close content: " + uri, e);
-                    }
-                }
             }
         } else {
             return Drawable.createFromPath(uri.toString());
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index 5f6d9ce..e58e62f 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -22,8 +22,8 @@
 import android.content.Context;
 import android.media.session.MediaController;
 import android.media.update.ApiLoader;
-import android.media.update.FrameLayoutHelper;
 import android.media.update.MediaControlView2Provider;
+import android.media.update.ViewGroupHelper;
 import android.util.AttributeSet;
 
 import java.lang.annotation.Retention;
@@ -61,7 +61,7 @@
  * TODO PUBLIC API
  * @hide
  */
-public class MediaControlView2 extends FrameLayoutHelper<MediaControlView2Provider> {
+public class MediaControlView2 extends ViewGroupHelper<MediaControlView2Provider> {
     /** @hide */
     @IntDef({
             BUTTON_PLAY_PAUSE,
@@ -155,10 +155,12 @@
 
     public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
-        super((instance, superProvider) ->
+        super((instance, superProvider, privateProvider) ->
                 ApiLoader.getProvider(context).createMediaControlView2(
-                        (MediaControlView2) instance, superProvider),
+                        (MediaControlView2) instance, superProvider, privateProvider,
+                        attrs, defStyleAttr, defStyleRes),
                 context, attrs, defStyleAttr, defStyleRes);
+        mProvider.initialize(attrs, defStyleAttr, defStyleRes);
     }
 
     /**
@@ -169,13 +171,6 @@
     }
 
     /**
-     * Returns whether the control view is currently shown or hidden.
-     */
-    public boolean isShowing() {
-        return mProvider.isShowing_impl();
-    }
-
-    /**
      * Changes the visibility state of an individual button. Default value is View.Visible.
      *
      * @param button the {@code Button} assigned to individual buttons
@@ -223,9 +218,7 @@
     }
 
     @Override
-    // TODO Move this method to ViewProvider
-    public void onVisibilityAggregated(boolean isVisible) {
-
-        mProvider.onVisibilityAggregated_impl(isVisible);
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mProvider.onLayout_impl(changed, l, t, r, b);
     }
 }
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 78ca011..3081180 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -27,8 +27,8 @@
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.media.update.ApiLoader;
-import android.media.update.FrameLayoutHelper;
 import android.media.update.VideoView2Provider;
+import android.media.update.ViewGroupHelper;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.AttributeSet;
@@ -101,7 +101,7 @@
  *
  * @hide
  */
-public class VideoView2 extends FrameLayoutHelper<VideoView2Provider> {
+public class VideoView2 extends ViewGroupHelper<VideoView2Provider> {
     /** @hide */
     @IntDef({
             VIEW_TYPE_TEXTUREVIEW,
@@ -139,10 +139,12 @@
     public VideoView2(
             @NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
-        super((instance, superProvider) ->
+        super((instance, superProvider, privateProvider) ->
                 ApiLoader.getProvider(context).createVideoView2(
-                        (VideoView2) instance, superProvider, attrs, defStyleAttr, defStyleRes),
+                        (VideoView2) instance, superProvider, privateProvider,
+                        attrs, defStyleAttr, defStyleRes),
                 context, attrs, defStyleAttr, defStyleRes);
+        mProvider.initialize(attrs, defStyleAttr, defStyleRes);
     }
 
     /**
@@ -487,4 +489,9 @@
          */
         void onCustomAction(String action, Bundle extras);
     }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mProvider.onLayout_impl(changed, l, t, r, b);
+    }
 }
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
index bb75bf6..fa8db96 100644
--- a/core/java/com/android/internal/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -31,7 +31,9 @@
     private static final String TAG = "AlsaCardsParser";
     protected static final boolean DEBUG = false;
 
-    private static final String kCardsFilePath = "/proc/asound/cards";
+    private static final String kAlsaFolderPath = "/proc/asound";
+    private static final String kCardsFilePath = kAlsaFolderPath + "/cards";
+    private static final String kDeviceAddressPrefix = "/dev/bus/usb/";
 
     private static LineTokenizer mTokenizer = new LineTokenizer(" :[]");
 
@@ -47,14 +49,31 @@
         private static final String TAG = "AlsaCardRecord";
         private static final String kUsbCardKeyStr = "at usb-";
 
-        public int mCardNum = -1;
-        public String mField1 = "";
-        public String mCardName = "";
-        public String mCardDescription = "";
-        public boolean mIsUsb = false;
+        int mCardNum = -1;
+        String mField1 = "";
+        String mCardName = "";
+        String mCardDescription = "";
+
+        private String mUsbDeviceAddress = null;
 
         public AlsaCardRecord() {}
 
+        public int getCardNum() {
+            return mCardNum;
+        }
+
+        public String getCardName() {
+            return mCardName;
+        }
+
+        public String getCardDescription() {
+            return mCardDescription;
+        }
+
+        public void setDeviceAddress(String usbDeviceAddress) {
+            mUsbDeviceAddress = usbDeviceAddress;
+        }
+
         private boolean parse(String line, int lineIndex) {
             int tokenIndex = 0;
             int delimIndex = 0;
@@ -87,8 +106,8 @@
                   tokenIndex = mTokenizer.nextToken(line, 0);
                   if (tokenIndex != -1) {
                       int keyIndex = line.indexOf(kUsbCardKeyStr);
-                      mIsUsb = keyIndex != -1;
-                      if (mIsUsb) {
+                      boolean isUsb = keyIndex != -1;
+                      if (isUsb) {
                           mCardDescription = line.substring(tokenIndex, keyIndex - 1);
                       }
                   }
@@ -97,14 +116,18 @@
             return true;
         }
 
+        boolean isUsb() {
+            return mUsbDeviceAddress != null;
+        }
+
         public String textFormat() {
-          return mCardName + " : " + mCardDescription;
+          return mCardName + " : " + mCardDescription + " [addr:" + mUsbDeviceAddress + "]";
         }
 
         public void log(int listIndex) {
             Slog.d(TAG, "" + listIndex +
                 " [" + mCardNum + " " + mCardName + " : " + mCardDescription +
-                " usb:" + mIsUsb);
+                " usb:" + isUsb());
         }
     }
 
@@ -112,7 +135,7 @@
 
     public int scan() {
         if (DEBUG) {
-            Slog.i(TAG, "AlsaCardsParser.scan()....");
+            Slog.d(TAG, "AlsaCardsParser.scan()....");
         }
 
         mCardRecords = new ArrayList<AlsaCardRecord>();
@@ -125,7 +148,7 @@
             while ((line = bufferedReader.readLine()) != null) {
                 AlsaCardRecord cardRecord = new AlsaCardRecord();
                 if (DEBUG) {
-                    Slog.i(TAG, "  " + line);
+                    Slog.d(TAG, "  " + line);
                 }
                 cardRecord.parse(line, 0);
 
@@ -134,10 +157,23 @@
                     break;
                 }
                 if (DEBUG) {
-                    Slog.i(TAG, "  " + line);
+                    Slog.d(TAG, "  " + line);
                 }
                 cardRecord.parse(line, 1);
 
+                // scan "usbbus" file
+                int cardNum = cardRecord.mCardNum;
+                String cardFolderPath = kAlsaFolderPath + "/card" + cardNum;
+                File usbbusFile = new File(cardFolderPath + "/usbbus");
+                if (usbbusFile.exists()) {
+                    // read it in
+                    FileReader usbbusReader = new FileReader(usbbusFile);
+                    String deviceAddress = (new BufferedReader(usbbusReader)).readLine();
+                    if (deviceAddress != null) {
+                        cardRecord.setDeviceAddress(kDeviceAddressPrefix + deviceAddress);
+                    }
+                    usbbusReader.close();
+                }
                 mCardRecords.add(cardRecord);
             }
             reader.close();
@@ -147,14 +183,12 @@
                 mScanStatus = SCANSTATUS_EMPTY;
             }
         } catch (FileNotFoundException e) {
-            e.printStackTrace();
             mScanStatus = SCANSTATUS_FAIL;
         } catch (IOException e) {
-            e.printStackTrace();
             mScanStatus = SCANSTATUS_FAIL;
         }
         if (DEBUG) {
-            Slog.i(TAG, "  status:" + mScanStatus);
+            Slog.d(TAG, "  status:" + mScanStatus);
         }
         return mScanStatus;
     }
@@ -163,142 +197,33 @@
         return mScanStatus;
     }
 
-    public ArrayList<AlsaCardRecord> getScanRecords() {
-        return mCardRecords;
-    }
-
-    public AlsaCardRecord getCardRecordAt(int index) {
-        return mCardRecords.get(index);
-    }
-
-    public AlsaCardRecord getCardRecordFor(int cardNum) {
-        for (AlsaCardRecord rec : mCardRecords) {
-            if (rec.mCardNum == cardNum) {
-                return rec;
+    public AlsaCardRecord findCardNumFor(String deviceAddress) {
+        for(AlsaCardRecord cardRec : mCardRecords) {
+            if (cardRec.isUsb() && cardRec.mUsbDeviceAddress.equals(deviceAddress)) {
+                return cardRec;
             }
         }
-
         return null;
     }
 
-    public int getNumCardRecords() {
-        return mCardRecords.size();
-    }
-
-    public boolean isCardUsb(int cardNum) {
-        for (AlsaCardRecord rec : mCardRecords) {
-            if (rec.mCardNum == cardNum) {
-                return rec.mIsUsb;
-            }
-        }
-
-        return false;
-    }
-
-    // return -1 if none found
-    public int getDefaultUsbCard() {
-        // save the current list of devices
-        ArrayList<AlsaCardsParser.AlsaCardRecord> prevRecs = mCardRecords;
-        if (DEBUG) {
-            LogDevices("Previous Devices:", prevRecs);
-        }
-
-        // get the new list of devices
-        if (scan() != SCANSTATUS_SUCCESS) {
-            Slog.e(TAG, "Error scanning Alsa cards file.");
-            return -1;
-        }
-
-        if (DEBUG) {
-            LogDevices("Current Devices:", mCardRecords);
-        }
-
-        // Calculate the difference between the old and new device list
-        ArrayList<AlsaCardRecord> newRecs = getNewCardRecords(prevRecs);
-        if (DEBUG) {
-            LogDevices("New Devices:", newRecs);
-        }
-
-        // Choose the most-recently added EXTERNAL card
-        // Check recently added devices
-        for (AlsaCardRecord rec : newRecs) {
-            if (DEBUG) {
-                Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
-            }
-            if (rec.mIsUsb) {
-                // Found it
-                return rec.mCardNum;
-            }
-        }
-
-        // or return the first added EXTERNAL card?
-        for (AlsaCardRecord rec : prevRecs) {
-            if (DEBUG) {
-                Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
-            }
-            if (rec.mIsUsb) {
-                return rec.mCardNum;
-            }
-        }
-
-        return -1;
-    }
-
-    public int getDefaultCard() {
-        // return an external card if possible
-        int card = getDefaultUsbCard();
-        if (DEBUG) {
-            Slog.d(TAG, "getDefaultCard() default usb card:" + card);
-        }
-
-        if (card < 0 && getNumCardRecords() > 0) {
-            // otherwise return the (internal) card with the highest number
-            card = getCardRecordAt(getNumCardRecords() - 1).mCardNum;
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "  returns card:" + card);
-        }
-        return card;
-    }
-
-    static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) {
-        for (AlsaCardRecord cardRec : recs) {
-            if (cardRec.mCardNum == cardNum) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) {
-        ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>();
-        for (AlsaCardRecord rec : mCardRecords) {
-            // now scan to see if this card number is in the previous scan list
-            if (!hasCardNumber(prevScanRecs, rec.mCardNum)) {
-                newRecs.add(rec);
-            }
-        }
-        return newRecs;
-    }
-
     //
     // Logging
     //
     private void Log(String heading) {
         if (DEBUG) {
-            Slog.i(TAG, heading);
+            Slog.d(TAG, heading);
             for (AlsaCardRecord cardRec : mCardRecords) {
-                Slog.i(TAG, cardRec.textFormat());
+                Slog.d(TAG, cardRec.textFormat());
             }
         }
     }
 
-    static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) {
-        Slog.d(TAG, caption + " ----------------");
-        int listIndex = 0;
-        for (AlsaCardRecord device : deviceList) {
-            device.log(listIndex++);
-        }
-        Slog.d(TAG, "----------------");
-    }
+//    static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) {
+//        Slog.d(TAG, caption + " ----------------");
+//        int listIndex = 0;
+//        for (AlsaCardRecord device : deviceList) {
+//            device.log(listIndex++);
+//        }
+//        Slog.d(TAG, caption + "----------------");
+//    }
 }
diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
index 15261baf..8d92d01 100644
--- a/core/java/com/android/internal/alsa/AlsaDevicesParser.java
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -27,6 +27,9 @@
  * @hide
  * Retrieves information from an ALSA "devices" file.
  */
+/*
+ * NOTE: This class is currently not being used, but may be needed in the future.
+ */
 public class AlsaDevicesParser {
     private static final String TAG = "AlsaDevicesParser";
     protected static final boolean DEBUG = false;
@@ -207,12 +210,6 @@
     //
     // Predicates
     //
-/*
-   public boolean hasPlaybackDevices() {
-        return mHasPlaybackDevices;
-    }
-*/
-
     public boolean hasPlaybackDevices(int card) {
         for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
             if (deviceRecord.mCardNum == card &&
@@ -224,12 +221,6 @@
         return false;
     }
 
-/*
-    public boolean hasCaptureDevices() {
-        return mHasCaptureDevices;
-    }
-*/
-
     public boolean hasCaptureDevices(int card) {
         for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
             if (deviceRecord.mCardNum == card &&
@@ -241,12 +232,6 @@
         return false;
     }
 
-/*
-    public boolean hasMIDIDevices() {
-        return mHasMIDIDevices;
-    }
-*/
-
     public boolean hasMIDIDevices(int card) {
         for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
             if (deviceRecord.mCardNum == card &&
@@ -280,6 +265,7 @@
                 if (isLineDeviceRecord(line)) {
                     AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
                     deviceRecord.parse(line);
+                    Slog.i(TAG, deviceRecord.textFormat());
                     mDeviceRecords.add(deviceRecord);
                 }
             }
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 902c8c1..6f7695c 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -21,24 +21,15 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.text.TextUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
 import android.view.Window;
-import android.widget.TextView;
 
 import com.android.internal.R;
 
@@ -85,14 +76,9 @@
             return;
         }
 
-        View rootView = LayoutInflater.from(this).inflate(R.layout.unlaunchable_app_activity, null);
-        TextView titleView = (TextView)rootView.findViewById(R.id.unlaunchable_app_title);
-        TextView messageView = (TextView)rootView.findViewById(R.id.unlaunchable_app_message);
-        titleView.setText(dialogTitle);
-        messageView.setText(dialogMessage);
-
         AlertDialog.Builder builder = new AlertDialog.Builder(this)
-                .setView(rootView)
+                .setTitle(dialogTitle)
+                .setMessage(dialogMessage)
                 .setOnDismissListener(this);
         if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
             builder.setPositiveButton(R.string.work_mode_turn_on, this)
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 39279b5..74802c8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,7 @@
                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                             instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
                             uuid, classLoaderContext, seInfo, false /* downgrade */,
-                            targetSdkVersion, /*profileName*/ null);
+                            targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null);
                 } catch (RemoteException | ServiceSpecificException e) {
                     // Ignore (but log), we need this on the classpath for fallback mode.
                     Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index 245a66e..1376687 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -96,4 +96,14 @@
                 context.getApplicationInfo().className,
                 StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
     }
+
+    public static void logAppOverlayEnter(int uid, String packageName, boolean usingAlertWindow) {
+        StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
+                StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED);
+    }
+
+    public static void logAppOverlayExit(int uid, String packageName, boolean usingAlertWindow) {
+        StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
+                StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED);
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ebb5f9f..f70d3c2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -132,6 +132,12 @@
     void clickQsTile(in ComponentName tile);
     void handleSystemKey(in int key);
 
+    /**
+     * Methods to show toast messages for screen pinning
+     */
+    void showPinningEnterExitToast(boolean entering);
+    void showPinningEscapeToast();
+
     void showShutdownUi(boolean isReboot, String reason);
 
     // Used to show the dialog when FingerprintService starts authentication
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index cb0b53c..adf4287 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -81,6 +81,12 @@
     void clickTile(in ComponentName tile);
     void handleSystemKey(in int key);
 
+    /**
+     * Methods to show toast messages for screen pinning
+     */
+    void showPinningEnterExitToast(boolean entering);
+    void showPinningEscapeToast();
+
     // Used to show the dialog when FingerprintService starts authentication
     void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
     // Used to hide the dialog when a finger is authenticated
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 5e0a986b..0282286 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -68,6 +68,7 @@
     void showInputMethodPickerFromClient(in IInputMethodClient client,
             int auxiliarySubtypeMode);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
+    boolean isInputMethodPickerShownForTest();
     void setInputMethod(in IBinder token, String id);
     void setInputMethodAndSubtype(in IBinder token, String id, in InputMethodSubtype subtype);
     void hideMySoftInput(in IBinder token, int flags);
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 5673814..732534c 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -66,6 +66,8 @@
     void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
     KeyChainSnapshot getKeyChainSnapshot();
     byte[] generateAndStoreKey(String alias);
+    String generateKey(String alias, in byte[] account);
+    String getKey(String alias);
     void removeKey(String alias);
     void setSnapshotCreatedPendingIntent(in PendingIntent intent);
     Map getRecoverySnapshotVersions();
diff --git a/core/java/com/android/server/backup/SliceBackupHelper.java b/core/java/com/android/server/backup/SliceBackupHelper.java
new file mode 100644
index 0000000..8e5a5ee
--- /dev/null
+++ b/core/java/com/android/server/backup/SliceBackupHelper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.server.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.app.slice.ISliceManager;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+public class SliceBackupHelper extends BlobBackupHelper {
+    static final String TAG = "SliceBackupHelper";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    // Current version of the blob schema
+    static final int BLOB_VERSION = 1;
+
+    // Key under which the payload blob is stored
+    static final String KEY_SLICES = "slices";
+
+    public SliceBackupHelper(Context context) {
+        super(BLOB_VERSION, KEY_SLICES);
+        // context is currently unused
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        byte[] newPayload = null;
+        if (KEY_SLICES.equals(key)) {
+            try {
+                ISliceManager sm = ISliceManager.Stub.asInterface(
+                        ServiceManager.getService(Context.SLICE_SERVICE));
+                // TODO: http://b/22388012
+                newPayload = sm.getBackupPayload(UserHandle.USER_SYSTEM);
+            } catch (Exception e) {
+                // Treat as no data
+                Slog.e(TAG, "Couldn't communicate with slice manager");
+                newPayload = null;
+            }
+        }
+        return newPayload;
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        if (DEBUG) Slog.v(TAG, "Got restore of " + key);
+
+        if (KEY_SLICES.equals(key)) {
+            try {
+                ISliceManager sm = ISliceManager.Stub.asInterface(
+                        ServiceManager.getService(Context.SLICE_SERVICE));
+                // TODO: http://b/22388012
+                sm.applyRestore(payload, UserHandle.USER_SYSTEM);
+            } catch (Exception e) {
+                Slog.e(TAG, "Couldn't communicate with slice manager");
+            }
+        }
+    }
+
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index a96b5dd..47e7a0e7 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -51,6 +51,7 @@
     private static final String USAGE_STATS_HELPER = "usage_stats";
     private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
     private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
+    private static final String SLICES_HELPER = "slices";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -88,6 +89,7 @@
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
         addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
+        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
         super.onBackup(oldState, data, newState);
     }
 
@@ -116,6 +118,7 @@
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
         addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
+        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
 
         super.onRestore(data, appVersionCode, newState);
     }
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index bfd575a..ff0f4fd 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -208,7 +208,7 @@
     optional SettingProto wifi_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_scan_always_available = 137 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_wakeup_enabled = 138 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto wifi_wakeup_available = 305 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    reserved 305; // Removed wifi_wakeup_available
     optional SettingProto network_scoring_ui_enabled = 306 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto speed_label_cache_eviction_age_millis = 307 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index aa2663f..0342c9c 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -27,6 +27,7 @@
 
 option java_multiple_files = true;
 
+// next ID: 43
 message AlarmManagerServiceProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -114,7 +115,14 @@
     optional int32 uid = 1;
     // In the 'elapsed' timebase.
     optional int64 time_ms = 2;
+
+    // Time when the next while-idle is allowed, in the 'elapsed' timebase.
+    optional int64 next_allowed_ms = 3;
   }
+
+  // Whether the short or long while-idle timeout should be used for each UID.
+  repeated int32 use_allow_while_idle_short_time = 42;
+
   // For each uid, this is the last time we dispatched an "allow while idle"
   // alarm, used to determine the earliest we can dispatch the next such alarm.
   repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 36;
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 43c869c..5296e47 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -24,14 +24,19 @@
 option java_multiple_files = true;
 
 // Dump from com.android.server.ForceAppStandbyTracker.
+//
+// Next ID: 12
 message ForceAppStandbyTrackerProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
   // Whether all apps are forced standby or not.
   optional bool force_all_apps_standby = 1;
 
+  // UIDs currently active.
+  repeated int32 active_uids = 2;
+
   // UIDs currently in the foreground.
-  repeated int32 foreground_uids = 2;
+  repeated int32 foreground_uids = 11;
 
   // App ids that are in power-save whitelist.
   repeated int32 power_save_whitelist_app_ids = 3;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c11058a..449e546 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -295,7 +295,6 @@
   optional bool animating_exit = 14;
   repeated WindowStateProto child_windows = 15;
   optional .android.graphics.RectProto surface_position = 16;
-  optional .android.graphics.RectProto shown_position = 17;
   optional int32 requested_width = 18;
   optional int32 requested_height = 19;
   optional int32 view_visibility = 20;
diff --git a/core/res/res/layout/unlaunchable_app_activity.xml b/core/res/res/layout/unlaunchable_app_activity.xml
deleted file mode 100644
index 429d5ed..0000000
--- a/core/res/res/layout/unlaunchable_app_activity.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="@dimen/dialog_padding"
-        android:orientation="vertical">
-        <TextView android:id="@+id/unlaunchable_app_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/dialog_padding"
-                android:paddingBottom="@dimen/dialog_padding"
-                android:textAppearance="@android:style/TextAppearance.Material.Title" />
-
-        <TextView android:id="@+id/unlaunchable_app_message"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/dialog_padding"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-                android:textColor="?android:attr/textColorSecondary" />
-</LinearLayout>
-
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 607414d..05d51ec 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -432,12 +432,6 @@
     <!-- Activity name to enable wifi tethering after provisioning app succeeds -->
     <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string>
 
-    <!-- Controls the WiFi wakeup feature.
-          0 = Not available.
-          1 = Available.
-     -->
-    <integer translatable="false" name="config_wifi_wakeup_available">1</integer>
-
     <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering.
 
          Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
@@ -1132,7 +1126,7 @@
     <bool name="config_hotswapCapable">false</bool>
 
     <!-- Component name of the ICC hotswap prompt for restart dialog -->
-    <string name="config_iccHotswapPromptForRestartDialogComponent" translateable="false">@null</string>
+    <string name="config_iccHotswapPromptForRestartDialogComponent" translatable="false">@null</string>
 
     <!-- Enable puk unlockscreen by default.
          If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
@@ -1431,7 +1425,7 @@
          permission.
          [This is only used if config_enableUpdateableTimeZoneRules and
          config_timeZoneRulesUpdateTrackingEnabled are true.] -->
-    <string name="config_timeZoneRulesUpdaterPackage" translateable="false">com.android.timezone.updater</string>
+    <string name="config_timeZoneRulesUpdaterPackage" translatable="false">com.android.timezone.updater</string>
 
     <!-- The package of the time zone rules data application. Expected to be configured
          by OEMs to reference their own priv-app APK package.
@@ -1440,7 +1434,7 @@
          data app packages.
          [This is only used if config_enableUpdateableTimeZoneRules and
          config_timeZoneRulesUpdateTrackingEnabled are true.] -->
-    <string name="config_timeZoneRulesDataPackage" translateable="false"></string>
+    <string name="config_timeZoneRulesDataPackage" translatable="false"></string>
 
     <!-- The allowed time in milliseconds between an update check intent being broadcast and the
          response being considered overdue. Reliability triggers will not fire in this time.
@@ -3258,7 +3252,7 @@
     <string translatable="false" name="config_deviceSpecificAudioService"></string>
 
     <!-- Component name of media projection permission dialog -->
-    <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+    <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
 
     <!-- Corner radius of system dialogs -->
     <dimen name="config_dialogCornerRadius">2dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 224503b..ec81df7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1351,6 +1351,10 @@
     <string name="fingerprint_error_lockout_permanent">Too many attempts. Fingerprint sensor disabled.</string>
     <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
     <string name="fingerprint_error_unable_to_process">Try again.</string>
+    <!-- Generic error message shown when the user has no enrolled fingerprints -->
+    <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
+    <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
+    <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor</string>
 
     <!-- Template to be used to name enrolled fingerprints by default. -->
     <string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
@@ -4423,15 +4427,6 @@
     <!-- DO NOT TRANSLATE -->
     <string name="date_picker_day_typeface">sans-serif-medium</string>
 
-    <!-- Notify use that they are in Lock-to-app -->
-    <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back and Overview
-        buttons</string>
-
-    <!-- Starting lock-to-app indication. -->
-    <string name="lock_to_app_start">Screen pinned</string>
-    <!-- Exting lock-to-app indication. -->
-    <string name="lock_to_app_exit">Screen unpinned</string>
-
     <!-- Lock-to-app unlock pin string -->
     <string name="lock_to_app_unlock_pin">Ask for PIN before unpinning</string>
     <!-- Lock-to-app unlock pattern string -->
@@ -4815,7 +4810,7 @@
     A toast message shown when an app shortcut that was restored from a previous device is clicked,
     but it cannot be started because the shortcut was created by a newer version of the app.
     -->
-    <string name="shortcut_restored_on_lower_version">This shortcut requires latest app</string>
+    <string name="shortcut_restored_on_lower_version">App version downgraded, or isn\u2019t compatible with this shortcut</string>
 
     <!--
     A toast message shown when an app shortcut that was restored from a previous device is clicked,
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a338f89..2ed94a0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -767,9 +767,6 @@
   <java-symbol type="string" name="kilobyteShort" />
   <java-symbol type="string" name="last_month" />
   <java-symbol type="string" name="launchBrowserDefault" />
-  <java-symbol type="string" name="lock_to_app_toast" />
-  <java-symbol type="string" name="lock_to_app_start" />
-  <java-symbol type="string" name="lock_to_app_exit" />
   <java-symbol type="string" name="lock_to_app_unlock_pin" />
   <java-symbol type="string" name="lock_to_app_unlock_pattern" />
   <java-symbol type="string" name="lock_to_app_unlock_password" />
@@ -2155,7 +2152,6 @@
   <java-symbol type="string" name="config_mobile_hotspot_provision_response" />
   <java-symbol type="integer" name="config_mobile_hotspot_provision_check_period" />
   <java-symbol type="string" name="config_wifi_tether_enable" />
-  <java-symbol type="integer" name="config_wifi_wakeup_available" />
   <java-symbol type="bool" name="config_intrusiveNotificationLed" />
   <java-symbol type="bool" name="config_notificationBadging" />
   <java-symbol type="dimen" name="preference_fragment_padding_bottom" />
@@ -2354,6 +2350,8 @@
   <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
   <java-symbol type="string" name="fingerprint_name_template" />
   <java-symbol type="string" name="fingerprint_not_recognized" />
+  <java-symbol type="string" name="fingerprint_error_no_fingerprints" />
+  <java-symbol type="string" name="fingerprint_error_hw_not_present" />
 
   <!-- Fingerprint config -->
   <java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
@@ -2702,9 +2700,6 @@
   <java-symbol type="string" name="language_selection_title" />
   <java-symbol type="string" name="search_language_hint" />
 
-  <java-symbol type="layout" name="unlaunchable_app_activity" />
-  <java-symbol type="id" name="unlaunchable_app_title" />
-  <java-symbol type="id" name="unlaunchable_app_message" />
   <java-symbol type="string" name="work_mode_off_title" />
   <java-symbol type="string" name="work_mode_off_message" />
   <java-symbol type="string" name="work_mode_turn_on" />
@@ -3153,6 +3148,7 @@
   <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" />
   <java-symbol type="string" name="config_headlineFontFamily" />
   <java-symbol type="string" name="config_headlineFontFamilyLight" />
+  <java-symbol type="string" name="config_headlineFontFamilyMedium" />
 
   <java-symbol type="drawable" name="stat_sys_vitals" />
 
diff --git a/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
index 4f7c924..5989da7 100644
--- a/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
+++ b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
@@ -54,7 +54,7 @@
         for (int i = 0; i < reps; i++) {
             try (FileInputStream in = new FileInputStream(mSrc);
                     FileOutputStream out = new FileOutputStream(mDest)) {
-                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
@@ -63,7 +63,7 @@
         for (int i = 0; i < reps; i++) {
             try (FileInputStream in = new FileInputStream(mSrc);
                     FileOutputStream out = new FileOutputStream(mDest)) {
-                copyInternalSendfile(in.getFD(), out.getFD(), null, null);
+                copyInternalSendfile(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
@@ -72,7 +72,7 @@
         for (int i = 0; i < reps; i++) {
             try (MemoryPipe in = MemoryPipe.createSource(mData);
                     FileOutputStream out = new FileOutputStream(mDest)) {
-                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
@@ -81,7 +81,7 @@
         for (int i = 0; i < reps; i++) {
             try (MemoryPipe in = MemoryPipe.createSource(mData);
                     FileOutputStream out = new FileOutputStream(mDest)) {
-                copyInternalSplice(in.getFD(), out.getFD(), null, null);
+                copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
@@ -90,7 +90,7 @@
         for (int i = 0; i < reps; i++) {
             try (FileInputStream in = new FileInputStream(mSrc);
                     MemoryPipe out = MemoryPipe.createSink(mData)) {
-                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
@@ -99,7 +99,7 @@
         for (int i = 0; i < reps; i++) {
             try (FileInputStream in = new FileInputStream(mSrc);
                     MemoryPipe out = MemoryPipe.createSink(mData)) {
-                copyInternalSplice(in.getFD(), out.getFD(), null, null);
+                copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
             }
         }
     }
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 27b7f9e..ea0347d 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -192,6 +192,12 @@
         assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
         assertEquals("example2.com", uri.getHost());
         assertEquals(-1, uri.getPort());
+        assertEquals("/path", uri.getPath());
+
+        uri = Uri.parse("http://a.foo.com\\.example.com/path");
+        assertEquals("a.foo.com", uri.getHost());
+        assertEquals(-1, uri.getPort());
+        assertEquals("\\.example.com/path", uri.getPath());
     }
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index b7220b3..0bc3a2d 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -181,6 +181,27 @@
     }
 
     @Test
+    public void testCopy_ShortPipeToFile() throws Exception {
+        byte[] source = new byte[33_000_000];
+        new Random().nextBytes(source);
+
+        for (int size : DATA_SIZES) {
+            final File dest = new File(mTarget, "dest");
+
+            byte[] expected = Arrays.copyOf(source, size);
+            byte[] actual = new byte[size];
+
+            try (MemoryPipe in = MemoryPipe.createSource(source);
+                    FileOutputStream out = new FileOutputStream(dest)) {
+                FileUtils.copy(in.getFD(), out.getFD(), null, null, size);
+            }
+
+            actual = readFile(dest);
+            assertArrayEquals(expected, actual);
+        }
+    }
+
+    @Test
     public void testIsFilenameSafe() throws Exception {
         assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
         assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0083b01..83d0719 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -436,7 +436,6 @@
                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
                     Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
                     Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
-                    Settings.Global.WIFI_WAKEUP_AVAILABLE,
                     Settings.Global.WIFI_WATCHDOG_ON,
                     Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                     Settings.Global.WINDOW_ANIMATION_SCALE,
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
new file mode 100644
index 0000000..4ca3e4c
--- /dev/null
+++ b/core/tests/overlaytests/device/Android.mk
@@ -0,0 +1,31 @@
+# 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_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_TARGET_REQUIRED_MODULES := \
+    OverlayDeviceTests_AppOverlayOne \
+    OverlayDeviceTests_AppOverlayTwo \
+    OverlayDeviceTests_FrameworkOverlay
+include $(BUILD_PACKAGE)
+
+# Include to build test-apps.
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index e01caee..d14fdf5 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -15,15 +15,15 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.server.om.test">
+    package="com.android.overlaytest">
 
     <uses-sdk android:minSdkVersion="21" />
 
     <application>
-        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner"/>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.server.om.test" />
-
+        android:targetPackage="com.android.overlaytest"
+        android:label="Runtime resource overlay tests" />
 </manifest>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
new file mode 100644
index 0000000..f069835
--- /dev/null
+++ b/core/tests/overlaytests/device/AndroidTest.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.
+-->
+
+<configuration description="Test module config for OverlayDeviceTests">
+    <option name="test-tag" value="OverlayDeviceTests" />
+    <option name="test-suite-tag" value="apct" />
+
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="OverlayDeviceTests.apk" />
+        <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
+        <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
+        <option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command"
+                value="cmd overlay disable com.android.overlaytest.framework" />
+        <option name="run-command"
+                value="cmd overlay disable com.android.overlaytest.app_overlay_one" />
+        <option name="run-command"
+                value="cmd overlay disable com.android.overlaytest.app_overlay_two" />
+        <option name="teardown-command"
+                value="cmd overlay disable com.android.overlaytest.framework" />
+        <option name="teardown-command"
+                value="cmd overlay disable com.android.overlaytest.app_overlay_one" />
+        <option name="teardown-command"
+                value="cmd overlay disable com.android.overlaytest.app_overlay_two" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.overlaytest" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk b/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk
deleted file mode 100644
index f76de7a..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := system_current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.filtered_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml
deleted file mode 100644
index 5b7950a..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.overlaytest.filtered_app_overlay"
-        android:versionCode="1"
-        android:versionName="1.0">
-        <overlay android:targetPackage="com.android.overlaytest"
-                android:requiredSystemPropertyName="persist.oem.overlay.test"
-                android:requiredSystemPropertyValue="foo"
-                android:priority="3"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt
deleted file mode 100644
index 0954ced..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt
+++ /dev/null
@@ -1 +0,0 @@
-Lorem ipsum: filtered overlays.
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml b/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml
deleted file mode 100644
index 60b94ee..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="str">filtered</string>
-</resources>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml b/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml
deleted file mode 100644
index e2652b7..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<integer value="3"/>
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/Android.mk b/core/tests/overlaytests/device/OverlayAppFirst/Android.mk
deleted file mode 100644
index bf9416c..0000000
--- a/core/tests/overlaytests/device/OverlayAppFirst/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.first_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml
deleted file mode 100644
index ec10bbc..0000000
--- a/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.overlaytest.first_app_overlay"
-        android:versionCode="1"
-        android:versionName="1.0">
-        <overlay android:targetPackage="com.android.overlaytest" android:priority="1"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/Android.mk b/core/tests/overlaytests/device/OverlayAppSecond/Android.mk
deleted file mode 100644
index bb7d142..0000000
--- a/core/tests/overlaytests/device/OverlayAppSecond/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.second_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml
deleted file mode 100644
index ed49863..0000000
--- a/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.overlaytest.second_app_overlay"
-        android:versionCode="1"
-        android:versionName="1.0">
-        <overlay android:targetPackage="com.android.overlaytest" android:priority="2"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/Android.mk b/core/tests/overlaytests/device/OverlayTest/Android.mk
deleted file mode 100644
index 5fe7b91..0000000
--- a/core/tests/overlaytests/device/OverlayTest/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PACKAGE_NAME := OverlayTest
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVA_LIBRARIES += android.test.base
-
-LOCAL_MODULE_PATH := $(TARGET_OUT)/app
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml
deleted file mode 100644
index 9edba12..0000000
--- a/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.overlaytest">
-    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION"/>
-    <application>
-        <uses-library android:name="android.test.runner"/>
-    </application>
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="com.android.overlaytest"
-        android:label="Runtime resource overlay tests"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
deleted file mode 100644
index e104f5a..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithMultipleOverlaysTest extends OverlayBaseTest {
-    public WithMultipleOverlaysTest() {
-        mMode = MODE_MULTIPLE_OVERLAYS;
-    }
-}
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
deleted file mode 100644
index 816a476..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithOverlayTest extends OverlayBaseTest {
-    public WithOverlayTest() {
-        mMode = MODE_SINGLE_OVERLAY;
-    }
-}
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
deleted file mode 100644
index 318cccc..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithoutOverlayTest extends OverlayBaseTest {
-    public WithoutOverlayTest() {
-        mMode = MODE_NO_OVERLAY;
-    }
-}
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk
deleted file mode 100644
index ed330467..0000000
--- a/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml
deleted file mode 100644
index f8b6c7b..0000000
--- a/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.overlaytest.overlay"
-        android:versionCode="1"
-        android:versionName="1.0">
-        <overlay android:targetPackage="android" android:priority="1"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/device/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/drawable-nodpi/drawable.jpg
rename to core/tests/overlaytests/device/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/device/OverlayTest/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayTest/res/values-sv/config.xml b/core/tests/overlaytests/device/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/values-sv/config.xml
rename to core/tests/overlaytests/device/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/res/values/config.xml b/core/tests/overlaytests/device/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/values/config.xml
rename to core/tests/overlaytests/device/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/res/xml/integer.xml b/core/tests/overlaytests/device/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/xml/integer.xml
rename to core/tests/overlaytests/device/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
similarity index 76%
rename from core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
rename to core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index e57c55c..96ab977 100644
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -1,45 +1,80 @@
+/*
+ * 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.overlaytest;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.app.UiAutomation;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
+import android.os.LocaleList;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
 import android.util.AttributeSet;
 import android.util.Xml;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 
-public abstract class OverlayBaseTest extends AndroidTestCase {
+@Ignore
+public abstract class OverlayBaseTest {
     private Resources mResources;
-    protected int mMode; // will be set by subclasses
-    static final protected int MODE_NO_OVERLAY = 0;
-    static final protected int MODE_SINGLE_OVERLAY = 1;
-    static final protected int MODE_MULTIPLE_OVERLAYS = 2;
+    private final int mMode;
+    static final int MODE_NO_OVERLAY = 0;
+    static final int MODE_SINGLE_OVERLAY = 1;
+    static final int MODE_MULTIPLE_OVERLAYS = 2;
 
-    protected void setUp() {
-        mResources = getContext().getResources();
+    static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+    static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+    static final String FRAMEWORK_OVERLAY_PKG = "com.android.overlaytest.framework";
+
+    protected OverlayBaseTest(int mode) {
+        mMode = mode;
+    }
+
+    @Before
+    public void setUp() {
+        mResources = InstrumentationRegistry.getContext().getResources();
     }
 
     private int calculateRawResourceChecksum(int resId) throws Throwable {
-        InputStream input = null;
-        try {
-            input = mResources.openRawResource(resId);
+        try (InputStream input = mResources.openRawResource(resId)) {
             int ch, checksum = 0;
             while ((ch = input.read()) != -1) {
                 checksum = (checksum + ch) % 0xffddbb00;
             }
             return checksum;
-        } finally {
-            input.close();
         }
     }
 
     private void setLocale(Locale locale) {
-        Locale.setDefault(locale);
+        final LocaleList locales = new LocaleList(locale);
+        LocaleList.setDefault(locales);
         Configuration config = new Configuration();
-        config.locale = locale;
+        config.setLocales(locales);
         mResources.updateConfiguration(config, mResources.getDisplayMetrics());
     }
 
@@ -126,6 +161,7 @@
         }
     }
 
+    @Test
     public void testFrameworkBooleanOverlay() throws Throwable {
         // config_annoy_dianne has the value:
         // - true when no overlay exists (MODE_NO_OVERLAY)
@@ -135,6 +171,7 @@
         assertResource(resId, true, false, false);
     }
 
+    @Test
     public void testBooleanOverlay() throws Throwable {
         // usually_false has the value:
         // - false when no overlay exists (MODE_NO_OVERLAY)
@@ -144,12 +181,14 @@
         assertResource(resId, false, true, false);
     }
 
+    @Test
     public void testBoolean() throws Throwable {
         // always_true has no overlay
         final int resId = R.bool.always_true;
         assertResource(resId, true, true, true);
     }
 
+    @Test
     public void testIntegerArrayOverlay() throws Throwable {
         // fibonacci has values:
         // - eight first values of Fibonacci sequence, when no overlay exists (MODE_NO_OVERLAY)
@@ -162,6 +201,7 @@
                 new int[]{21, 13, 8, 5, 3, 2, 1, 1});
     }
 
+    @Test
     public void testIntegerArray() throws Throwable {
         // prime_numbers has no overlay
         final int resId = R.array.prime_numbers;
@@ -169,6 +209,7 @@
         assertResource(resId, expected, expected, expected);
     }
 
+    @Test
     public void testDrawable() throws Throwable {
         // drawable-nodpi/drawable has overlay (default config)
         final int resId = R.drawable.drawable;
@@ -188,16 +229,19 @@
         assertEquals(expected, actual);
     }
 
+    @Test
     public void testAppString() throws Throwable {
         final int resId = R.string.str;
         assertResource(resId, "none", "single", "multiple");
     }
 
+    @Test
     public void testApp2() throws Throwable {
         final int resId = R.string.str2; // only in base package and first app overlay
         assertResource(resId, "none", "single", "single");
     }
 
+    @Test
     public void testAppXml() throws Throwable {
         int expected = getExpected(0, 1, 2);
         int actual = -1;
@@ -214,6 +258,7 @@
         assertEquals(expected, actual);
     }
 
+    @Test
     public void testAppRaw() throws Throwable {
         final int resId = R.raw.lorem_ipsum;
 
@@ -256,10 +301,10 @@
      * SLOT  PACKAGE           CONFIGURATION  VALUE
      * A     target package    (default)      100
      * B     target package    -sv            200
-     * C     OverlayAppFirst   (default)      300
-     * D     OverlayAppFirst   -sv            400
-     * E     OverlayAppSecond  (default)      500
-     * F     OverlayAppSecond  -sv            600
+     * C     AppOverlayOne     (default)      300
+     * D     AppOverlayOne     -sv            400
+     * E     AppOverlayTwo     (default)      500
+     * F     AppOverlayTwo     -sv            600
      *
      * Example: in testMatrix101110, the base package defines the
      * R.integer.matrix101110 resource for the default configuration (value
@@ -269,195 +314,283 @@
      * are loaded, the expected value after setting the language to Swedish is
      * 400.
      */
+    @Test
     public void testMatrix100000() throws Throwable {
         final int resId = R.integer.matrix_100000;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 100);
     }
 
+    @Test
     public void testMatrix100001() throws Throwable {
         final int resId = R.integer.matrix_100001;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 600);
     }
 
+    @Test
     public void testMatrix100010() throws Throwable {
         final int resId = R.integer.matrix_100010;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 500);
     }
 
+    @Test
     public void testMatrix100011() throws Throwable {
         final int resId = R.integer.matrix_100011;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 600);
     }
 
+    @Test
     public void testMatrix100100() throws Throwable {
         final int resId = R.integer.matrix_100100;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
+    @Test
     public void testMatrix100101() throws Throwable {
         final int resId = R.integer.matrix_100101;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
+    @Test
     public void testMatrix100110() throws Throwable {
         final int resId = R.integer.matrix_100110;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
+    @Test
     public void testMatrix100111() throws Throwable {
         final int resId = R.integer.matrix_100111;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
+    @Test
     public void testMatrix101000() throws Throwable {
         final int resId = R.integer.matrix_101000;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 300);
     }
 
+    @Test
     public void testMatrix101001() throws Throwable {
         final int resId = R.integer.matrix_101001;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 600);
     }
 
+    @Test
     public void testMatrix101010() throws Throwable {
         final int resId = R.integer.matrix_101010;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 500);
     }
 
+    @Test
     public void testMatrix101011() throws Throwable {
         final int resId = R.integer.matrix_101011;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 600);
     }
 
+    @Test
     public void testMatrix101100() throws Throwable {
         final int resId = R.integer.matrix_101100;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
+    @Test
     public void testMatrix101101() throws Throwable {
         final int resId = R.integer.matrix_101101;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
+    @Test
     public void testMatrix101110() throws Throwable {
         final int resId = R.integer.matrix_101110;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
+    @Test
     public void testMatrix101111() throws Throwable {
         final int resId = R.integer.matrix_101111;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
+    @Test
     public void testMatrix110000() throws Throwable {
         final int resId = R.integer.matrix_110000;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
+    @Test
     public void testMatrix110001() throws Throwable {
         final int resId = R.integer.matrix_110001;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
+    @Test
     public void testMatrix110010() throws Throwable {
         final int resId = R.integer.matrix_110010;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
+    @Test
     public void testMatrix110011() throws Throwable {
         final int resId = R.integer.matrix_110011;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
+    @Test
     public void testMatrix110100() throws Throwable {
         final int resId = R.integer.matrix_110100;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
+    @Test
     public void testMatrix110101() throws Throwable {
         final int resId = R.integer.matrix_110101;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
+    @Test
     public void testMatrix110110() throws Throwable {
         final int resId = R.integer.matrix_110110;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
+    @Test
     public void testMatrix110111() throws Throwable {
         final int resId = R.integer.matrix_110111;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
+    @Test
     public void testMatrix111000() throws Throwable {
         final int resId = R.integer.matrix_111000;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
+    @Test
     public void testMatrix111001() throws Throwable {
         final int resId = R.integer.matrix_111001;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
+    @Test
     public void testMatrix111010() throws Throwable {
         final int resId = R.integer.matrix_111010;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
+    @Test
     public void testMatrix111011() throws Throwable {
         final int resId = R.integer.matrix_111011;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
+    @Test
     public void testMatrix111100() throws Throwable {
         final int resId = R.integer.matrix_111100;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
+    @Test
     public void testMatrix111101() throws Throwable {
         final int resId = R.integer.matrix_111101;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
+    @Test
     public void testMatrix111110() throws Throwable {
         final int resId = R.integer.matrix_111110;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
+    @Test
     public void testMatrix111111() throws Throwable {
         final int resId = R.integer.matrix_111111;
         setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
+
+    /**
+     * Executes the shell command and reads all the output to ensure the command ran and didn't
+     * get stuck buffering on output.
+     */
+    protected static String executeShellCommand(UiAutomation automation, String command)
+            throws Exception {
+        final ParcelFileDescriptor pfd = automation.executeShellCommand(command);
+        try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            final BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(in, StandardCharsets.UTF_8));
+            StringBuilder str = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                str.append(line);
+            }
+            return str.toString();
+        }
+    }
+
+    /**
+     * Enables overlay packages and waits for a configuration change event before
+     * returning, to guarantee that Resources are up-to-date.
+     * @param packages the list of package names to enable.
+     */
+    protected static void enableOverlayPackages(String... packages) throws Exception {
+        enableOverlayPackages(true, packages);
+    }
+
+    /**
+     * Disables overlay packages and waits for a configuration change event before
+     * returning, to guarantee that Resources are up-to-date.
+     * @param packages the list of package names to disable.
+     */
+    protected static void disableOverlayPackages(String... packages) throws Exception {
+        enableOverlayPackages(false, packages);
+    }
+
+    /**
+     * Enables/disables overlay packages and waits for a configuration change event before
+     * returning, to guarantee that Resources are up-to-date.
+     * @param enable enables the overlays when true, disables when false.
+     * @param packages the list of package names to enable/disable.
+     */
+    private static void enableOverlayPackages(boolean enable, String[] packages)
+            throws Exception {
+        final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation();
+        for (final String pkg : packages) {
+            executeShellCommand(uiAutomation,
+                    "cmd overlay " + (enable ? "enable " : "disable ") + pkg);
+        }
+
+        // Wait for the overlay change to propagate.
+        Thread.sleep(1000);
+    }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
new file mode 100644
index 0000000..f35e511
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithMultipleOverlaysTest extends OverlayBaseTest {
+    public WithMultipleOverlaysTest() {
+        super(MODE_MULTIPLE_OVERLAYS);
+    }
+
+    @BeforeClass
+    public static void enableOverlay() throws Exception {
+        enableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
+    }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
new file mode 100644
index 0000000..037449f
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithOverlayTest extends OverlayBaseTest {
+    public WithOverlayTest() {
+        super(MODE_SINGLE_OVERLAY);
+    }
+
+    @BeforeClass
+    public static void enableOverlay() throws Exception {
+        disableOverlayPackages(APP_OVERLAY_TWO_PKG);
+        enableOverlayPackages(APP_OVERLAY_ONE_PKG, FRAMEWORK_OVERLAY_PKG);
+    }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
new file mode 100644
index 0000000..f657b5c
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithoutOverlayTest extends OverlayBaseTest {
+    public WithoutOverlayTest() {
+        super(MODE_NO_OVERLAY);
+    }
+
+    @BeforeClass
+    public static void disableOverlays() throws Exception {
+        disableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
+    }
+}
diff --git a/core/tests/overlaytests/device/test-apps/Android.mk b/core/tests/overlaytests/device/test-apps/Android.mk
new file mode 100644
index 0000000..9af9f444
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/Android.mk
@@ -0,0 +1,15 @@
+# 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.
+
+include $(call all-subdir-makefiles)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
new file mode 100644
index 0000000..17e20ee
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -0,0 +1,22 @@
+# 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_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
new file mode 100644
index 0000000..1719158
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?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.android.overlaytest.app_overlay_one"
+        android:versionCode="1"
+        android:versionName="1.0">
+        <overlay android:targetPackage="com.android.overlaytest" android:priority="1" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/values-sv/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/values-sv/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/values/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/xml/integer.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/xml/integer.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
new file mode 100644
index 0000000..c24bea9
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -0,0 +1,22 @@
+# 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_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
new file mode 100644
index 0000000..ae8307c
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?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.android.overlaytest.app_overlay_two"
+        android:versionCode="1"
+        android:versionName="1.0">
+        <overlay android:targetPackage="com.android.overlaytest" android:priority="2" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/values-sv/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/values-sv/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/values/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/xml/integer.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/xml/integer.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
new file mode 100644
index 0000000..dc811c5
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -0,0 +1,22 @@
+# 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_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..77ea16a
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?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.android.overlaytest.framework"
+        android:versionCode="1"
+        android:versionName="1.0">
+        <overlay android:targetPackage="android" android:priority="1" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTestOverlay/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/FrameworkOverlay/res/values/config.xml
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
index 2d68439..b08ac96 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
@@ -15,6 +15,6 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.server.om.hosttest.signature_overlay">
+    package="com.android.server.om.hosttest.signature_overlay">
     <overlay android:targetPackage="android" />
 </manifest>
diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py
deleted file mode 100755
index e88805e..0000000
--- a/core/tests/overlaytests/testrunner.py
+++ /dev/null
@@ -1,732 +0,0 @@
-#!/usr/bin/python
-import hashlib
-import optparse
-import os
-import re
-import shlex
-import subprocess
-import sys
-import threading
-import time
-
-TASK_COMPILATION = 'compile'
-TASK_DISABLE_OVERLAYS = 'disable overlays'
-TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays'
-TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay'
-TASK_ENABLE_FILTERED_OVERLAYS = 'enable filtered overlays'
-TASK_FILE_EXISTS_TEST = 'test (file exists)'
-TASK_GREP_IDMAP_TEST = 'test (grep idmap)'
-TASK_MD5_TEST = 'test (md5)'
-TASK_IDMAP_PATH = 'idmap --path'
-TASK_IDMAP_SCAN = 'idmap --scan'
-TASK_INSTRUMENTATION = 'instrumentation'
-TASK_INSTRUMENTATION_TEST = 'test (instrumentation)'
-TASK_MKDIR = 'mkdir'
-TASK_PUSH = 'push'
-TASK_ROOT = 'root'
-TASK_REMOUNT = 'remount'
-TASK_RM = 'rm'
-TASK_SETPROP = 'setprop'
-TASK_SETUP_IDMAP_PATH = 'setup idmap --path'
-TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan'
-TASK_START = 'start'
-TASK_STOP = 'stop'
-
-adb = 'adb'
-
-def _adb_shell(cmd):
-    argv = shlex.split(adb + " shell '" + cmd + "; echo $?'")
-    proc = subprocess.Popen(argv, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    (stdout, stderr) = proc.communicate()
-    (stdout, stderr) = (stdout.replace('\r', ''), stderr.replace('\r', ''))
-    tmp = stdout.rsplit('\n', 2)
-    if len(tmp) == 2:
-        stdout == ''
-        returncode = int(tmp[0])
-    else:
-        stdout = tmp[0] + '\n'
-        returncode = int(tmp[1])
-    return returncode, stdout, stderr
-
-class VerbosePrinter:
-    class Ticker(threading.Thread):
-        def _print(self):
-            s = '\r' + self.text + '[' + '.' * self.i + ' ' * (4 - self.i) + ']'
-            sys.stdout.write(s)
-            sys.stdout.flush()
-            self.i = (self.i + 1) % 5
-
-        def __init__(self, cond_var, text):
-            threading.Thread.__init__(self)
-            self.text = text
-            self.setDaemon(True)
-            self.cond_var = cond_var
-            self.running = False
-            self.i = 0
-            self._print()
-            self.running = True
-
-        def run(self):
-            self.cond_var.acquire()
-            while True:
-                self.cond_var.wait(0.25)
-                running = self.running
-                if not running:
-                    break
-                self._print()
-            self.cond_var.release()
-
-        def stop(self):
-            self.cond_var.acquire()
-            self.running = False
-            self.cond_var.notify_all()
-            self.cond_var.release()
-
-    def _start_ticker(self):
-        self.ticker = VerbosePrinter.Ticker(self.cond_var, self.text)
-        self.ticker.start()
-
-    def _stop_ticker(self):
-        self.ticker.stop()
-        self.ticker.join()
-        self.ticker = None
-
-    def _format_begin(self, type, name):
-        N = self.width - len(type) - len(' [    ] ')
-        fmt = '%%s %%-%ds ' % N
-        return fmt % (type, name)
-
-    def __init__(self, use_color):
-        self.cond_var = threading.Condition()
-        self.ticker = None
-        if use_color:
-            self.color_RED = '\033[1;31m'
-            self.color_red = '\033[0;31m'
-            self.color_reset = '\033[0;37m'
-        else:
-            self.color_RED = ''
-            self.color_red = ''
-            self.color_reset = ''
-
-        argv = shlex.split('stty size') # get terminal width
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        if proc.returncode == 0:
-            (h, w) = stdout.split()
-            self.width = int(w)
-        else:
-            self.width = 72 # conservative guesstimate
-
-    def begin(self, type, name):
-        self.text = self._format_begin(type, name)
-        sys.stdout.write(self.text + '[    ]')
-        sys.stdout.flush()
-        self._start_ticker()
-
-    def end_pass(self, type, name):
-        self._stop_ticker()
-        sys.stdout.write('\r' + self.text + '[ OK ]\n')
-        sys.stdout.flush()
-
-    def end_fail(self, type, name, msg):
-        self._stop_ticker()
-        sys.stdout.write('\r' + self.color_RED + self.text + '[FAIL]\n')
-        sys.stdout.write(self.color_red)
-        sys.stdout.write(msg)
-        sys.stdout.write(self.color_reset)
-        sys.stdout.flush()
-
-class QuietPrinter:
-    def begin(self, type, name):
-        pass
-
-    def end_pass(self, type, name):
-        sys.stdout.write('PASS ' + type + ' ' + name + '\n')
-        sys.stdout.flush()
-
-    def end_fail(self, type, name, msg):
-        sys.stdout.write('FAIL ' + type + ' ' + name + '\n')
-        sys.stdout.flush()
-
-class CompilationTask:
-    def __init__(self, makefile):
-        self.makefile = makefile
-
-    def get_type(self):
-        return TASK_COMPILATION
-
-    def get_name(self):
-        return self.makefile
-
-    def execute(self):
-        os.putenv('ONE_SHOT_MAKEFILE', os.getcwd() + "/" + self.makefile)
-        argv = shlex.split('make -C "../../../../../" files')
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        return proc.returncode, stdout, stderr
-
-class InstrumentationTask:
-    def __init__(self, instrumentation_class):
-        self.instrumentation_class = instrumentation_class
-
-    def get_type(self):
-        return TASK_INSTRUMENTATION
-
-    def get_name(self):
-        return self.instrumentation_class
-
-    def execute(self):
-        return _adb_shell('am instrument -r -w -e class %s com.android.overlaytest/android.test.InstrumentationTestRunner' % self.instrumentation_class)
-
-class PushTask:
-    def __init__(self, src, dest):
-        self.src = src
-        self.dest = dest
-
-    def get_type(self):
-        return TASK_PUSH
-
-    def get_name(self):
-        return "%s -> %s" % (self.src, self.dest)
-
-    def execute(self):
-        src = os.getenv('OUT')
-        if (src is None):
-          return 1, "", "Unable to proceed - $OUT environment var not set\n"
-        src += "/" + self.src
-        argv = shlex.split(adb + ' push %s %s' % (src, self.dest))
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        return proc.returncode, stdout, stderr
-
-class MkdirTask:
-    def __init__(self, path):
-        self.path = path
-
-    def get_type(self):
-        return TASK_MKDIR
-
-    def get_name(self):
-        return self.path
-
-    def execute(self):
-        return _adb_shell('mkdir -p %s' % self.path)
-
-class RmTask:
-    def __init__(self, path):
-        self.path = path
-
-    def get_type(self):
-        return TASK_RM
-
-    def get_name(self):
-        return self.path
-
-    def execute(self):
-        returncode, stdout, stderr = _adb_shell('ls %s' % self.path)
-        if returncode != 0 and stderr.endswith(': No such file or directory\n'):
-            return 0, "", ""
-        return _adb_shell('rm -r %s' % self.path)
-
-class SetPropTask:
-    def __init__(self, prop, value):
-        self.prop = prop
-        self.value = value
-
-    def get_type(self):
-        return TASK_SETPROP
-
-    def get_name(self):
-        return self.prop
-
-    def execute(self):
-      return _adb_shell('setprop %s %s' % (self.prop, self.value))
-
-class IdmapPathTask:
-    def __init__(self, path_target_apk, path_overlay_apk, path_idmap):
-        self.path_target_apk = path_target_apk
-        self.path_overlay_apk = path_overlay_apk
-        self.path_idmap = path_idmap
-
-    def get_type(self):
-        return TASK_IDMAP_PATH
-
-    def get_name(self):
-        return self.path_idmap
-
-    def execute(self):
-        return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.target_pkg_name, self.target_pkg, self.idmap_dir, self.overlay_dir))
-
-class IdmapScanTask:
-    def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir):
-        self.overlay_dir = overlay_dir
-        self.target_pkg_name = target_pkg_name
-        self.target_pkg = target_pkg
-        self.idmap_dir = idmap_dir
-        self.symlink_dir = symlink_dir
-
-    def get_type(self):
-        return TASK_IDMAP_SCAN
-
-    def get_name(self):
-        return self.target_pkg_name
-
-    def execute(self):
-        return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.overlay_dir, self.target_pkg_name, self.target_pkg, self.idmap_dir))
-
-class FileExistsTest:
-    def __init__(self, path):
-        self.path = path
-
-    def get_type(self):
-        return TASK_FILE_EXISTS_TEST
-
-    def get_name(self):
-        return self.path
-
-    def execute(self):
-        return _adb_shell('ls %s' % self.path)
-
-class GrepIdmapTest:
-    def __init__(self, path_idmap, pattern, expected_n):
-        self.path_idmap = path_idmap
-        self.pattern = pattern
-        self.expected_n = expected_n
-
-    def get_type(self):
-        return TASK_GREP_IDMAP_TEST
-
-    def get_name(self):
-        return self.pattern
-
-    def execute(self):
-        returncode, stdout, stderr = _adb_shell('idmap --inspect %s' % self.path_idmap)
-        if returncode != 0:
-            return returncode, stdout, stderr
-        all_matches = re.findall('\s' + self.pattern + '$', stdout, flags=re.MULTILINE)
-        if len(all_matches) != self.expected_n:
-            return 1, 'pattern=%s idmap=%s expected=%d found=%d\n' % (self.pattern, self.path_idmap, self.expected_n, len(all_matches)), ''
-        return 0, "", ""
-
-class Md5Test:
-    def __init__(self, path, expected_content):
-        self.path = path
-        self.expected_md5 = hashlib.md5(expected_content).hexdigest()
-
-    def get_type(self):
-        return TASK_MD5_TEST
-
-    def get_name(self):
-        return self.path
-
-    def execute(self):
-        returncode, stdout, stderr = _adb_shell('md5sum %s' % self.path)
-        if returncode != 0:
-            return returncode, stdout, stderr
-        actual_md5 = stdout.split()[0]
-        if actual_md5 != self.expected_md5:
-            return 1, 'expected %s, got %s\n' % (self.expected_md5, actual_md5), ''
-        return 0, "", ""
-
-class StartTask:
-    def get_type(self):
-        return TASK_START
-
-    def get_name(self):
-        return ""
-
-    def execute(self):
-        (returncode, stdout, stderr) = _adb_shell('start')
-        if returncode != 0:
-            return returncode, stdout, stderr
-
-        while True:
-            (returncode, stdout, stderr) = _adb_shell('getprop dev.bootcomplete')
-            if returncode != 0:
-                return returncode, stdout, stderr
-            if stdout.strip() == "1":
-                break
-            time.sleep(0.5)
-
-        return 0, "", ""
-
-class StopTask:
-    def get_type(self):
-        return TASK_STOP
-
-    def get_name(self):
-        return ""
-
-    def execute(self):
-        (returncode, stdout, stderr) = _adb_shell('stop')
-        if returncode != 0:
-            return returncode, stdout, stderr
-        return _adb_shell('setprop dev.bootcomplete 0')
-
-class RootTask:
-    def get_type(self):
-        return TASK_ROOT
-
-    def get_name(self):
-        return ""
-
-    def execute(self):
-        (returncode, stdout, stderr) = _adb_shell('getprop service.adb.root 0')
-        if returncode != 0:
-            return returncode, stdout, stderr
-        if stdout.strip() == '1': # already root
-            return 0, "", ""
-
-        argv = shlex.split(adb + ' root')
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        if proc.returncode != 0:
-            return proc.returncode, stdout, stderr
-
-        argv = shlex.split(adb + ' wait-for-device')
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        return proc.returncode, stdout, stderr
-
-class RemountTask:
-    def get_type(self):
-        return TASK_REMOUNT
-
-    def get_name(self):
-        return ""
-
-    def execute(self):
-        argv = shlex.split(adb + ' remount')
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (stdout, stderr) = proc.communicate()
-        # adb remount returns 0 even if the operation failed, so check stdout
-        if stdout.startswith('remount failed:'):
-            return 1, stdout, stderr
-        return proc.returncode, stdout, stderr
-
-class CompoundTask:
-    def __init__(self, type, tasks):
-        self.type = type
-        self.tasks = tasks
-
-    def get_type(self):
-        return self.type
-
-    def get_name(self):
-        return ""
-
-    def execute(self):
-        for t in self.tasks:
-            (returncode, stdout, stderr) = t.execute()
-            if returncode != 0:
-                return returncode, stdout, stderr
-        return 0, "", ""
-
-def _create_disable_overlays_task():
-    tasks = [
-        RmTask("/vendor/overlay/framework_a.apk"),
-        RmTask("/vendor/overlay/framework_b.apk"),
-        RmTask("/data/resource-cache/vendor@overlay@framework_a.apk@idmap"),
-        RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"),
-        RmTask("/vendor/overlay/app_a.apk"),
-        RmTask("/vendor/overlay/app_b.apk"),
-        RmTask("/vendor/overlay/app_c.apk"),
-        RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"),
-        RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"),
-        RmTask("/data/resource-cache/vendor@overlay@app_c.apk@idmap"),
-        SetPropTask('persist.oem.overlay.test', '""'),
-        RmTask("/data/property/persist.oem.overlay.test"),
-    ]
-    return CompoundTask(TASK_DISABLE_OVERLAYS, tasks)
-
-def _create_enable_single_overlay_task():
-    tasks = [
-        _create_disable_overlays_task(),
-        MkdirTask('/system/vendor'),
-        MkdirTask('/vendor/overlay'),
-        PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
-        PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
-    ]
-    return CompoundTask(TASK_ENABLE_SINGLE_OVERLAY, tasks)
-
-def _create_enable_multiple_overlays_task():
-    tasks = [
-        _create_disable_overlays_task(),
-        MkdirTask('/system/vendor'),
-        MkdirTask('/vendor/overlay'),
-
-        PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
-        PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
-        PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
-        PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'),
-    ]
-    return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks)
-
-def _create_enable_filtered_overlays_task():
-      tasks = [
-        _create_disable_overlays_task(),
-        SetPropTask('persist.oem.overlay.test', 'foo'),
-        MkdirTask('/system/vendor'),
-        MkdirTask('/vendor/overlay'),
-        PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
-        PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
-        PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
-        PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'),
-      ]
-      return CompoundTask(TASK_ENABLE_FILTERED_OVERLAYS, tasks)
-
-def _create_setup_idmap_path_task(idmaps, symlinks):
-    tasks = [
-        _create_enable_single_overlay_task(),
-        RmTask(symlinks),
-        RmTask(idmaps),
-        MkdirTask(idmaps),
-        MkdirTask(symlinks),
-    ]
-    return CompoundTask(TASK_SETUP_IDMAP_PATH, tasks)
-
-def _create_setup_idmap_scan_task(idmaps, symlinks):
-    tasks = [
-        _create_enable_filtered_overlays_task(),
-        RmTask(symlinks),
-        RmTask(idmaps),
-        MkdirTask(idmaps),
-        MkdirTask(symlinks),
-    ]
-    return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks)
-
-def _handle_instrumentation_task_output(stdout, printer):
-    regex_status_code = re.compile(r'^INSTRUMENTATION_STATUS_CODE: -?(\d+)')
-    regex_name = re.compile(r'^INSTRUMENTATION_STATUS: test=(.*)')
-    regex_begin_stack = re.compile(r'^INSTRUMENTATION_STATUS: stack=(.*)')
-    regex_end_stack = re.compile(r'^$')
-
-    failed_tests = 0
-    current_test = None
-    current_stack = []
-    mode_stack = False
-    for line in stdout.split("\n"):
-        line = line.rstrip() # strip \r from adb output
-        m = regex_status_code.match(line)
-        if m:
-            c = int(m.group(1))
-            if c == 1:
-                printer.begin(TASK_INSTRUMENTATION_TEST, current_test)
-            elif c == 0:
-                printer.end_pass(TASK_INSTRUMENTATION_TEST, current_test)
-            else:
-                failed_tests += 1
-                current_stack.append("\n")
-                msg = "\n".join(current_stack)
-                printer.end_fail(TASK_INSTRUMENTATION_TEST, current_test, msg.rstrip() + '\n')
-            continue
-
-        m = regex_name.match(line)
-        if m:
-            current_test = m.group(1)
-            continue
-
-        m = regex_begin_stack.match(line)
-        if m:
-            mode_stack = True
-            current_stack = []
-            current_stack.append("  " + m.group(1))
-            continue
-
-        m = regex_end_stack.match(line)
-        if m:
-            mode_stack = False
-            continue
-
-        if mode_stack:
-            current_stack.append("    " + line.strip())
-
-    return failed_tests
-
-def _set_adb_device(option, opt, value, parser):
-    global adb
-    if opt == '-d' or opt == '--device':
-        adb = 'adb -d'
-    if opt == '-e' or opt == '--emulator':
-        adb = 'adb -e'
-    if opt == '-s' or opt == '--serial':
-        adb = 'adb -s ' + value
-
-def _create_opt_parser():
-    parser = optparse.OptionParser()
-    parser.add_option('-d', '--device', action='callback', callback=_set_adb_device,
-            help='pass -d to adb')
-    parser.add_option('-e', '--emulator', action='callback', callback=_set_adb_device,
-            help='pass -e to adb')
-    parser.add_option('-s', '--serial', type="str", action='callback', callback=_set_adb_device,
-            help='pass -s <serical> to adb')
-    parser.add_option('-C', '--no-color', action='store_false',
-            dest='use_color', default=True,
-            help='disable color escape sequences in output')
-    parser.add_option('-q', '--quiet', action='store_true',
-            dest='quiet_mode', default=False,
-            help='quiet mode, output only results')
-    parser.add_option('-b', '--no-build', action='store_false',
-            dest='do_build', default=True,
-            help='do not rebuild test projects')
-    parser.add_option('-k', '--continue', action='store_true',
-            dest='do_continue', default=False,
-            help='do not rebuild test projects')
-    parser.add_option('-i', '--test-idmap', action='store_true',
-            dest='test_idmap', default=False,
-            help='run tests for idmap')
-    parser.add_option('-0', '--test-no-overlay', action='store_true',
-            dest='test_no_overlay', default=False,
-            help='run tests without any overlay')
-    parser.add_option('-1', '--test-single-overlay', action='store_true',
-            dest='test_single_overlay', default=False,
-            help='run tests for single overlay')
-    parser.add_option('-2', '--test-multiple-overlays', action='store_true',
-            dest='test_multiple_overlays', default=False,
-            help='run tests for multiple overlays')
-    parser.add_option('-3', '--test-filtered-overlays', action='store_true',
-            dest='test_filtered_overlays', default=False,
-            help='run tests for filtered (sys prop) overlays')
-    return parser
-
-if __name__ == '__main__':
-    opt_parser = _create_opt_parser()
-    opts, args = opt_parser.parse_args(sys.argv[1:])
-    if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays and not opts.test_filtered_overlays:
-        opts.test_idmap = True
-        opts.test_no_overlay = True
-        opts.test_single_overlay = True
-        opts.test_multiple_overlays = True
-        opts.test_filtered_overlays = True
-
-    if len(args) > 0:
-        opt_parser.error("unexpected arguments: %s" % " ".join(args))
-        # will never reach this: opt_parser.error will call sys.exit
-
-    if opts.quiet_mode:
-        printer = QuietPrinter()
-    else:
-        printer = VerbosePrinter(opts.use_color)
-    tasks = []
-
-    # must be in the same directory as this script for compilation tasks to work
-    script = sys.argv[0]
-    dirname = os.path.dirname(script)
-    wd = os.path.realpath(dirname)
-    os.chdir(wd)
-
-    # build test cases
-    if opts.do_build:
-        tasks.append(CompilationTask('OverlayTest/Android.mk'))
-        tasks.append(CompilationTask('OverlayTestOverlay/Android.mk'))
-        tasks.append(CompilationTask('OverlayAppFirst/Android.mk'))
-        tasks.append(CompilationTask('OverlayAppSecond/Android.mk'))
-        tasks.append(CompilationTask('OverlayAppFiltered/Android.mk'))
-
-    # remount filesystem, install test project
-    tasks.append(RootTask())
-    tasks.append(RemountTask())
-    tasks.append(PushTask('/system/app/OverlayTest/OverlayTest.apk', '/system/app/OverlayTest.apk'))
-
-    # test idmap
-    if opts.test_idmap:
-        idmaps='/data/local/tmp/idmaps'
-        symlinks='/data/local/tmp/symlinks'
-
-        # idmap --path
-        tasks.append(StopTask())
-        tasks.append(_create_setup_idmap_path_task(idmaps, symlinks))
-        tasks.append(StartTask())
-        tasks.append(IdmapPathTask('/vendor/overlay/framework_a.apk', '/system/framework/framework-res.apk', idmaps + '/a.idmap'))
-        tasks.append(FileExistsTest(idmaps + '/a.idmap'))
-        tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1))
-
-        # idmap --scan
-        tasks.append(StopTask())
-        tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks))
-        tasks.append(StartTask())
-        tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks))
-        tasks.append(FileExistsTest(idmaps + '/vendor@overlay@framework_b.apk@idmap'))
-        tasks.append(GrepIdmapTest(idmaps + '/vendor@overlay@framework_b.apk@idmap', 'bool/config_annoy_dianne', 1))
-
-
-        # overlays.list
-        overlays_list_path = idmaps + '/overlays.list'
-        expected_content = '''\
-/vendor/overlay/framework_b.apk /data/local/tmp/idmaps/vendor@overlay@framework_b.apk@idmap
-'''
-        tasks.append(FileExistsTest(overlays_list_path))
-        tasks.append(Md5Test(overlays_list_path, expected_content))
-
-        # idmap cleanup
-        tasks.append(RmTask(symlinks))
-        tasks.append(RmTask(idmaps))
-
-    # test no overlay: all overlays cleared
-    if opts.test_no_overlay:
-        tasks.append(StopTask())
-        tasks.append(_create_disable_overlays_task())
-        tasks.append(StartTask())
-        tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest'))
-
-    # test single overlay: one overlay (a)
-    if opts.test_single_overlay:
-        tasks.append(StopTask())
-        tasks.append(_create_enable_single_overlay_task())
-        tasks.append(StartTask())
-        tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest'))
-
-    # test multiple overlays: all overlays - including 'disabled' filtered
-    # overlay (system property unset) so expect 'b[p=2]' overrides 'a[p=1]' but
-    # 'c[p=3]' should be ignored
-    if opts.test_multiple_overlays:
-        tasks.append(StopTask())
-        tasks.append(_create_enable_multiple_overlays_task())
-        tasks.append(StartTask())
-        tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest'))
-
-    # test filtered overlays: all overlays - including 'enabled' filtered
-    # overlay (system property set/matched) so expect c[p=3] to override both a
-    # & b where applicable
-    if opts.test_filtered_overlays:
-        tasks.append(StopTask())
-        tasks.append(_create_enable_filtered_overlays_task())
-        tasks.append(StartTask())
-        tasks.append(InstrumentationTask('com.android.overlaytest.WithFilteredOverlaysTest'))
-
-    ignored_errors = 0
-    for t in tasks:
-        type = t.get_type()
-        name = t.get_name()
-        if type == TASK_INSTRUMENTATION:
-            # InstrumentationTask will run several tests, but we want it
-            # to appear as if each test was run individually. Calling
-            # "am instrument" with a single test method is prohibitively
-            # expensive, so let's instead post-process the output to
-            # emulate individual calls.
-            retcode, stdout, stderr = t.execute()
-            if retcode != 0:
-                printer.begin(TASK_INSTRUMENTATION, name)
-                printer.end_fail(TASK_INSTRUMENTATION, name, stderr)
-                sys.exit(retcode)
-            retcode = _handle_instrumentation_task_output(stdout, printer)
-            if retcode != 0:
-                if not opts.do_continue:
-                    sys.exit(retcode)
-                else:
-                    ignored_errors += retcode
-        else:
-            printer.begin(type, name)
-            retcode, stdout, stderr = t.execute()
-            if retcode == 0:
-                printer.end_pass(type, name)
-            if retcode != 0:
-                if len(stderr) == 0:
-                    # hope for output from stdout instead (true for eg adb shell rm)
-                    stderr = stdout
-                printer.end_fail(type, name, stderr)
-                if not opts.do_continue:
-                    sys.exit(retcode)
-                else:
-                    ignored_errors += retcode
-    sys.exit(ignored_errors)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 773d4d3..bb9b89b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -158,6 +158,7 @@
         <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
         <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
         <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
@@ -228,6 +229,7 @@
         <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.MODIFY_AUDIO_ROUTING" />
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index dad24da..22867df 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -333,6 +333,9 @@
     <family lang="und-Cari">
         <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
     </family>
+    <family lang="und-Cakm">
+        <font weight="400" style="normal">NotoSansChakma-Regular.ttf</font>
+    </family>
     <family lang="und-Cher">
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
     </family>
@@ -429,6 +432,9 @@
     <family lang="und-Orkh">
         <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font>
     </family>
+    <family lang="und-Osge">
+        <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
+    </family>
     <family lang="und-Osma">
         <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font>
     </family>
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index bbf2145..acefead 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -74,7 +74,7 @@
         int getDensity() { return Bitmap.DENSITY_NONE; }
 
         /* @hide */
-        int computeDstDensity() {
+        final int computeDstDensity() {
             Resources res = getResources();
             if (res == null) {
                 return Bitmap.getDefaultDensity();
@@ -122,13 +122,19 @@
     }
 
     private static class ContentResolverSource extends Source {
-        ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri) {
+        ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri,
+                @Nullable Resources res) {
             mResolver = resolver;
             mUri = uri;
+            mResources = res;
         }
 
         private final ContentResolver mResolver;
         private final Uri mUri;
+        private final Resources mResources;
+
+        @Nullable
+        Resources getResources() { return mResources; }
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
@@ -438,6 +444,7 @@
     private boolean mPreferRamOverQuality = false;
     private boolean mAsAlphaMask = false;
     private Rect    mCropRect;
+    private Rect    mOutPaddingRect;
     private Source  mSource;
 
     private PostProcessor          mPostProcessor;
@@ -511,7 +518,18 @@
     @NonNull
     public static Source createSource(@NonNull ContentResolver cr,
             @NonNull Uri uri) {
-        return new ContentResolverSource(cr, uri);
+        return new ContentResolverSource(cr, uri, null);
+    }
+
+    /**
+     * Provide Resources for density scaling.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Source createSource(@NonNull ContentResolver cr,
+            @NonNull Uri uri, @Nullable Resources res) {
+        return new ContentResolverSource(cr, uri, res);
     }
 
     /**
@@ -765,6 +783,18 @@
     }
 
     /**
+     *  Set a Rect for retrieving nine patch padding.
+     *
+     *  If the image is a nine patch, this Rect will be set to the padding
+     *  rectangle during decode. Otherwise it will not be modified.
+     *
+     *  @hide
+     */
+    public void setOutPaddingRect(@NonNull Rect outPadding) {
+        mOutPaddingRect = outPadding;
+    }
+
+    /**
      *  Specify whether the {@link Bitmap} should be mutable.
      *
      *  <p>By default, a {@link Bitmap} created will be immutable, but that can
@@ -875,7 +905,6 @@
                 postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mRequireUnpremultiplied,
                 mPreferRamOverQuality, mAsAlphaMask);
-
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -948,7 +977,10 @@
             if (np != null && NinePatch.isNinePatchChunk(np)) {
                 Rect opticalInsets = new Rect();
                 bm.getOpticalInsets(opticalInsets);
-                Rect padding = new Rect();
+                Rect padding = decoder.mOutPaddingRect;
+                if (padding == null) {
+                    padding = new Rect();
+                }
                 nGetPadding(decoder.mNativePtr, padding);
                 return new NinePatchDrawable(res, bm, np, padding,
                         opticalInsets, null);
@@ -991,6 +1023,15 @@
             final int srcDensity = computeDensity(src, decoder);
             Bitmap bm = decoder.decodeBitmap();
             bm.setDensity(srcDensity);
+
+            Rect padding = decoder.mOutPaddingRect;
+            if (padding != null) {
+                byte[] np = bm.getNinePatchChunk();
+                if (np != null && NinePatch.isNinePatchChunk(np)) {
+                    nGetPadding(decoder.mNativePtr, padding);
+                }
+            }
+
             return bm;
         }
     }
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 7ad062a..44b783b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,6 +27,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Outline;
@@ -49,6 +50,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -111,7 +113,7 @@
      */
     @Deprecated
     public BitmapDrawable() {
-        mBitmapState = new BitmapState((Bitmap) null);
+        init(new BitmapState((Bitmap) null), null);
     }
 
     /**
@@ -124,8 +126,7 @@
     @SuppressWarnings("unused")
     @Deprecated
     public BitmapDrawable(Resources res) {
-        mBitmapState = new BitmapState((Bitmap) null);
-        mBitmapState.mTargetDensity = mTargetDensity;
+        init(new BitmapState((Bitmap) null), res);
     }
 
     /**
@@ -135,7 +136,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        this(new BitmapState(bitmap), null);
+        init(new BitmapState(bitmap), null);
     }
 
     /**
@@ -143,8 +144,7 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        this(new BitmapState(bitmap), res);
-        mBitmapState.mTargetDensity = mTargetDensity;
+        init(new BitmapState(bitmap), res);
     }
 
     /**
@@ -154,10 +154,7 @@
      */
     @Deprecated
     public BitmapDrawable(String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
-        }
+        this(null, filepath);
     }
 
     /**
@@ -165,10 +162,21 @@
      */
     @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
     public BitmapDrawable(Resources res, String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
-        mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+        Bitmap bitmap = null;
+        try (FileInputStream stream = new FileInputStream(filepath)) {
+            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
+                    (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (Exception e) {
+            /*  do nothing. This matches the behavior of BitmapFactory.decodeFile()
+                If the exception happened on decode, mBitmapState.mBitmap will be null.
+            */
+        } finally {
+            init(new BitmapState(bitmap), res);
+            if (mBitmapState.mBitmap == null) {
+                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+            }
         }
     }
 
@@ -179,10 +187,7 @@
      */
     @Deprecated
     public BitmapDrawable(java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
-        }
+        this(null, is);
     }
 
     /**
@@ -190,10 +195,21 @@
      */
     @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
     public BitmapDrawable(Resources res, java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
-        mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+        Bitmap bitmap = null;
+        try {
+            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
+                    (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (Exception e) {
+            /*  do nothing. This matches the behavior of BitmapFactory.decodeStream()
+                If the exception happened on decode, mBitmapState.mBitmap will be null.
+            */
+        } finally {
+            init(new BitmapState(bitmap), res);
+            if (mBitmapState.mBitmap == null) {
+                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+            }
         }
     }
 
@@ -812,9 +828,19 @@
                 }
             }
 
+            int density = Bitmap.DENSITY_NONE;
+            if (value.density == TypedValue.DENSITY_DEFAULT) {
+                density = DisplayMetrics.DENSITY_DEFAULT;
+            } else if (value.density != TypedValue.DENSITY_NONE) {
+                density = value.density;
+            }
+
             Bitmap bitmap = null;
             try (InputStream is = r.openRawResource(srcResId, value)) {
-                bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+                bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
             } catch (Exception e) {
                 // Do nothing and pick up the error below.
             }
@@ -1013,14 +1039,21 @@
         }
     }
 
+    private BitmapDrawable(BitmapState state, Resources res) {
+        init(state, res);
+    }
+
     /**
-     * The one constructor to rule them all. This is called by all public
+     * The one helper to rule them all. This is called by all public & private
      * constructors to set the state and initialize local properties.
      */
-    private BitmapDrawable(BitmapState state, Resources res) {
+    private void init(BitmapState state, Resources res) {
         mBitmapState = state;
-
         updateLocalState(res);
+
+        if (mBitmapState != null && res != null) {
+            mBitmapState.mTargetDensity = mTargetDensity;
+        }
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index f17cd76..36a4d26 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,6 +37,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
@@ -50,11 +51,13 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.View;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
@@ -1175,6 +1178,10 @@
             return null;
         }
 
+        if (opts == null) {
+            return getBitmapDrawable(res, value, is);
+        }
+
         /*  ugh. The decodeStream contract is that we have already allocated
             the pad rect, but if the bitmap does not had a ninepatch chunk,
             then the pad will be ignored. If we could change this to lazily
@@ -1207,6 +1214,33 @@
         return null;
     }
 
+    private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+        try {
+            ImageDecoder.Source source = null;
+            if (value != null) {
+                int density = Bitmap.DENSITY_NONE;
+                if (value.density == TypedValue.DENSITY_DEFAULT) {
+                    density = DisplayMetrics.DENSITY_DEFAULT;
+                } else if (value.density != TypedValue.DENSITY_NONE) {
+                    density = value.density;
+                }
+                source = ImageDecoder.createSource(res, is, density);
+            } else {
+                source = ImageDecoder.createSource(res, is);
+            }
+
+            return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (IOException e) {
+            /*  do nothing.
+                If the exception happened on decode, the drawable will be null.
+            */
+            Log.e("Drawable", "Unable to decode stream: " + e);
+        }
+        return null;
+    }
+
     /**
      * Create a drawable from an XML document. For more information on how to
      * create resources in XML, see
@@ -1306,11 +1340,10 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
-        try {
-            Bitmap bm = BitmapFactory.decodeFile(pathName);
-            if (bm != null) {
-                return drawableFromBitmap(null, bm, null, null, null, pathName);
-            }
+        try (FileInputStream stream = new FileInputStream(pathName)) {
+            return getBitmapDrawable(null, null, stream);
+        } catch(IOException e) {
+            // Do nothing; we will just return null if the FileInputStream had an error
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1790020..a56e8d1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -24,9 +24,9 @@
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
@@ -211,7 +211,8 @@
             restoreAlpha = -1;
         }
 
-        final boolean needsDensityScaling = canvas.getDensity() == 0;
+        final boolean needsDensityScaling = canvas.getDensity() == 0
+                && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
         if (needsDensityScaling) {
             restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
 
@@ -421,10 +422,6 @@
 
         final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
         if (srcResId != 0) {
-            final BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inDither = !state.mDither;
-            options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
             final Rect padding = new Rect();
             final Rect opticalInsets = new Rect();
             Bitmap bitmap = null;
@@ -433,7 +430,17 @@
                 final TypedValue value = new TypedValue();
                 final InputStream is = r.openRawResource(srcResId, value);
 
-                bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
+                int density = Bitmap.DENSITY_NONE;
+                if (value.density == TypedValue.DENSITY_DEFAULT) {
+                    density = DisplayMetrics.DENSITY_DEFAULT;
+                } else if (value.density != TypedValue.DENSITY_NONE) {
+                    density = value.density;
+                }
+                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+                bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+                    decoder.setOutPaddingRect(padding);
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
 
                 is.close();
             } catch (IOException e) {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 3323bce..24d819e 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -134,6 +134,8 @@
     name: "libhwui_defaults",
     defaults: ["hwui_defaults"],
 
+    shared_libs: ["libstatslog"],
+
     whole_static_libs: ["libskia"],
 
     srcs: [
@@ -318,7 +320,10 @@
         "libgmock",
         "libhwui_static_debug",
     ],
-    shared_libs: ["libmemunreachable"],
+    shared_libs: [
+        "libmemunreachable",
+        "libstatslog",
+    ],
     cflags: [
         "-include debug/wrap_gles.h",
         "-DHWUI_NULL_GPU",
@@ -383,7 +388,10 @@
 
     // set to libhwui_static_debug to skip actual GL commands
     whole_static_libs: ["libhwui"],
-    shared_libs: ["libmemunreachable"],
+    shared_libs: [
+        "libmemunreachable",
+        "libstatslog",
+    ],
 
     srcs: [
         "tests/macrobench/TestSceneRunner.cpp",
@@ -405,7 +413,10 @@
     ],
 
     whole_static_libs: ["libhwui_static_debug"],
-    shared_libs: ["libmemunreachable"],
+    shared_libs: [
+        "libmemunreachable",
+        "libstatslog",
+    ],
 
     srcs: [
         "tests/microbench/main.cpp",
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index f41956c..ab27a0d 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <statslog.h>
 #include <sys/mman.h>
 
 #include <algorithm>
@@ -164,6 +165,7 @@
         ALOGI("%s", ss.str().c_str());
         // Just so we have something that counts up, the value is largely irrelevant
         ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
+        android::util::stats_write(android::util::DAVEY_OCCURRED, ns2ms(totalDuration));
     }
 }
 
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index ebc14c8..091b526 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -182,10 +182,11 @@
 
     std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
             std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
-    std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
-            std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
-    std::shared_ptr<minikin::FontCollection> collection =
-            std::make_shared<minikin::FontCollection>(std::move(family));
+    std::vector<minikin::Font> fonts;
+    fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+
+    std::shared_ptr<minikin::FontCollection> collection = std::make_shared<minikin::FontCollection>(
+            std::make_shared<minikin::FontFamily>(std::move(fonts)));
 
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 66d6f52..2232c25 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -56,8 +56,9 @@
     LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
     std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
             std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
-    return std::make_shared<minikin::FontFamily>(
-            std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
+    std::vector<minikin::Font> fonts;
+    fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+    return std::make_shared<minikin::FontFamily>(std::move(fonts));
 }
 
 std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 1904d40..f24abae 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -249,15 +249,15 @@
     }
 
     uint32_t id = (uint32_t)fieldId;
+    size_t prevPos = mBuffer.wp()->pos();
     mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
-
     size_t sizePos = mBuffer.wp()->pos();
 
     mDepth++;
     mObjectId++;
     mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
 
-    mExpectedObjectToken = makeToken(get_varint_size(id),
+    mExpectedObjectToken = makeToken(sizePos - prevPos,
         (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
     return mExpectedObjectToken;
 }
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b32e539..fcdecba 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -172,6 +172,14 @@
         }
 
         /**
+         * @hide
+         */
+        @SystemApi
+        public PlaybackInfoProvider getProvider() {
+            return mProvider;
+        }
+
+        /**
          * Get the type of playback which affects volume handling. One of:
          * <ul>
          * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
@@ -199,9 +207,9 @@
         /**
          * Get the type of volume control that can be used. One of:
          * <ul>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
+         * <li>{@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}</li>
+         * <li>{@link VolumeProvider2#VOLUME_CONTROL_RELATIVE}</li>
+         * <li>{@link VolumeProvider2#VOLUME_CONTROL_FIXED}</li>
          * </ul>
          *
          * @return The type of volume control that may be used with this session.
@@ -472,7 +480,7 @@
 
     /**
      * Set the volume of the output this session is playing on. The command will be ignored if it
-     * does not support {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}.
+     * does not support {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
      * <p>
      * If the session is local playback, this changes the device's volume with the stream that
      * session's player is using. Flags will be specified for the {@link AudioManager}.
@@ -494,8 +502,8 @@
      * must be one of {@link AudioManager#ADJUST_LOWER},
      * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
      * The command will be ignored if the session does not support
-     * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
-     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}.
+     * {@link VolumeProvider2#VOLUME_CONTROL_RELATIVE} or
+     * {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
      * <p>
      * If the session is local playback, this changes the device's volume with the stream that
      * session's player is using. Flags will be specified for the {@link AudioManager}.
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index f88f9f2..a11768e 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -27,7 +27,6 @@
 import android.media.update.ApiLoader;
 import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
 import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
-import android.media.update.MediaSession2Provider;
 import android.media.update.MediaSessionService2Provider;
 import android.os.Bundle;
 
@@ -63,7 +62,8 @@
     public static final String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
 
     /**
-     * Session for the media library service.
+     * Session for the {@link MediaLibraryService2}. Build this object with
+     * {@link MediaLibrarySessionBuilder} and return in {@link #onCreateSession(String)}.
      */
     public static class MediaLibrarySession extends MediaSession2 {
         private final MediaLibrarySessionProvider mProvider;
@@ -101,6 +101,9 @@
         }
     }
 
+    /**
+     * Callback for the {@link MediaLibrarySession}.
+     */
     public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
 
         public MediaLibrarySessionCallback(Context context) {
@@ -200,6 +203,8 @@
     /**
      * Builder for {@link MediaLibrarySession}.
      */
+    // Override all methods just to show them with the type instead of generics in Javadoc.
+    // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
     public class MediaLibrarySessionBuilder extends BuilderBase<MediaLibrarySession,
             MediaLibrarySessionBuilder, MediaLibrarySessionCallback> {
         public MediaLibrarySessionBuilder(
@@ -210,6 +215,38 @@
                     context, (MediaLibrarySessionBuilder) instance, player, callbackExecutor,
                     callback));
         }
+
+        @Override
+        public MediaLibrarySessionBuilder setVolumeProvider(
+                @Nullable VolumeProvider2 volumeProvider) {
+            return super.setVolumeProvider(volumeProvider);
+        }
+
+        @Override
+        public MediaLibrarySessionBuilder setRatingType(int type) {
+            return super.setRatingType(type);
+        }
+
+        @Override
+        public MediaLibrarySessionBuilder setSessionActivity(@Nullable PendingIntent pi) {
+            return super.setSessionActivity(pi);
+        }
+
+        @Override
+        public MediaLibrarySessionBuilder setId(String id) {
+            return super.setId(id);
+        }
+
+        @Override
+        public MediaLibrarySessionBuilder setSessionCallback(
+                @NonNull Executor executor, @NonNull MediaLibrarySessionCallback callback) {
+            return super.setSessionCallback(executor, callback);
+        }
+
+        @Override
+        public MediaLibrarySession build() {
+            return super.build();
+        }
     }
 
     @Override
@@ -229,7 +266,7 @@
      * This method will be called on the main thread.
      *
      * @param sessionId session id written in the AndroidManifest.xml.
-     * @return a new browser session
+     * @return a new library session
      * @see MediaLibrarySessionBuilder
      * @see #getSession()
      * @throws RuntimeException if returned session is invalid
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index d84eedf..e331b2c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1671,35 +1671,6 @@
     public abstract void deselectTrack(int index);
 
     /**
-     * Sets the target UDP re-transmit endpoint for the low level player.
-     * Generally, the address portion of the endpoint is an IP multicast
-     * address, although a unicast address would be equally valid.  When a valid
-     * retransmit endpoint has been set, the media player will not decode and
-     * render the media presentation locally.  Instead, the player will attempt
-     * to re-multiplex its media data using the Android@Home RTP profile and
-     * re-transmit to the target endpoint.  Receiver devices (which may be
-     * either the same as the transmitting device or different devices) may
-     * instantiate, prepare, and start a receiver player using a setDataSource
-     * URL of the form...
-     *
-     * aahRX://&lt;multicastIP&gt;:&lt;port&gt;
-     *
-     * to receive, decode and render the re-transmitted content.
-     *
-     * setRetransmitEndpoint may only be called before setDataSource has been
-     * called; while the player is in the Idle state.
-     *
-     * @param endpoint the address and UDP port of the re-transmission target or
-     * null if no re-transmission is to be performed.
-     * @throws IllegalStateException if it is called in an invalid state
-     * @throws IllegalArgumentException if the retransmit endpoint is supplied,
-     * but invalid.
-     *
-     * {@hide} pending API council
-     */
-    public void setRetransmitEndpoint(InetSocketAddress endpoint) { }
-
-    /**
      * Releases the resources held by this {@code MediaPlayer2} object.
      *
      * It is considered good practice to call this method when you're
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 222c66e..e3d5ac0 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -2964,53 +2964,6 @@
     }
 
     /**
-     * Sets the target UDP re-transmit endpoint for the low level player.
-     * Generally, the address portion of the endpoint is an IP multicast
-     * address, although a unicast address would be equally valid.  When a valid
-     * retransmit endpoint has been set, the media player will not decode and
-     * render the media presentation locally.  Instead, the player will attempt
-     * to re-multiplex its media data using the Android@Home RTP profile and
-     * re-transmit to the target endpoint.  Receiver devices (which may be
-     * either the same as the transmitting device or different devices) may
-     * instantiate, prepare, and start a receiver player using a setDataSource
-     * URL of the form...
-     *
-     * aahRX://&lt;multicastIP&gt;:&lt;port&gt;
-     *
-     * to receive, decode and render the re-transmitted content.
-     *
-     * setRetransmitEndpoint may only be called before setDataSource has been
-     * called; while the player is in the Idle state.
-     *
-     * @param endpoint the address and UDP port of the re-transmission target or
-     * null if no re-transmission is to be performed.
-     * @throws IllegalStateException if it is called in an invalid state
-     * @throws IllegalArgumentException if the retransmit endpoint is supplied,
-     * but invalid.
-     *
-     * {@hide} pending API council
-     */
-    @Override
-    public void setRetransmitEndpoint(InetSocketAddress endpoint)
-            throws IllegalStateException, IllegalArgumentException
-    {
-        String addrString = null;
-        int port = 0;
-
-        if (null != endpoint) {
-            addrString = endpoint.getAddress().getHostAddress();
-            port = endpoint.getPort();
-        }
-
-        int ret = native_setRetransmitEndpoint(addrString, port);
-        if (ret != 0) {
-            throw new IllegalArgumentException("Illegal re-transmit endpoint; native ret " + ret);
-        }
-    }
-
-    private native final int native_setRetransmitEndpoint(String addrString, int port);
-
-    /**
      * Releases the resources held by this {@code MediaPlayer2} object.
      *
      * It is considered good practice to call this method when you're
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 5670bd8..ae2649a 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -580,8 +580,20 @@
     };
 
     /**
-     * Base builder class for MediaSession2 and its subclass.
-     *
+     * Base builder class for MediaSession2 and its subclass. Any change in this class should be
+     * also applied to the subclasses {@link MediaSession2.Builder} and
+     * {@link MediaLibraryService2.MediaLibrarySessionBuilder}.
+     * <p>
+     * APIs here should be package private, but should have documentations for developers.
+     * Otherwise, javadoc will generate documentation with the generic types such as follows.
+     * <pre>U extends BuilderBase<T, U, C> setSessionCallback(Executor executor, C callback)</pre>
+     * <p>
+     * This class is hidden to prevent from generating test stub, which fails with
+     * 'unexpected bound' because it tries to auto generate stub class as follows.
+     * <pre>abstract static class BuilderBase<
+     *      T extends android.media.MediaSession2,
+     *      U extends android.media.MediaSession2.BuilderBase<
+     *              T, U, C extends android.media.MediaSession2.SessionCallback>, C></pre>
      * @hide
      */
     static abstract class BuilderBase
@@ -599,9 +611,9 @@
          * <p>
          * Set {@code null} to reset.
          *
-         * @param volumeProvider The provider that will handle volume changes. Can be {@code null}
+         * @param volumeProvider The provider that will handle volume changes. Can be {@code null}.
          */
-        public U setVolumeProvider(@Nullable VolumeProvider volumeProvider) {
+        U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
             mProvider.setVolumeProvider_impl(volumeProvider);
             return (U) this;
         }
@@ -619,7 +631,7 @@
          * <li>{@link Rating2#RATING_THUMB_UP_DOWN}</li>
          * </ul>
          */
-        public U setRatingType(@Rating2.Style int type) {
+        U setRatingType(@Rating2.Style int type) {
             mProvider.setRatingType_impl(type);
             return (U) this;
         }
@@ -631,7 +643,7 @@
          *
          * @param pi The intent to launch to show UI for this session.
          */
-        public U setSessionActivity(@Nullable PendingIntent pi) {
+        U setSessionActivity(@Nullable PendingIntent pi) {
             mProvider.setSessionActivity_impl(pi);
             return (U) this;
         }
@@ -646,7 +658,7 @@
          * @throws IllegalArgumentException if id is {@code null}
          * @return
          */
-        public U setId(@NonNull String id) {
+        U setId(@NonNull String id) {
             mProvider.setId_impl(id);
             return (U) this;
         }
@@ -658,7 +670,7 @@
          * @param callback session callback.
          * @return
          */
-        public U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
+        U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
                 @NonNull C callback) {
             mProvider.setSessionCallback_impl(executor, callback);
             return (U) this;
@@ -671,7 +683,7 @@
          * @throws IllegalStateException if the session with the same id is already exists for the
          *      package.
          */
-        public T build() {
+        T build() {
             return mProvider.build_impl();
         }
     }
@@ -682,13 +694,44 @@
      * Any incoming event from the {@link MediaController2} will be handled on the thread
      * that created session with the {@link Builder#build()}.
      */
-    // TODO(jaewan): Add setRatingType()
-    // TODO(jaewan): Add setSessionActivity()
+    // Override all methods just to show them with the type instead of generics in Javadoc.
+    // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
     public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> {
         public Builder(Context context, @NonNull MediaPlayerInterface player) {
             super((instance) -> ApiLoader.getProvider(context).createMediaSession2Builder(
                     context, (Builder) instance, player));
         }
+
+        @Override
+        public Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
+            return super.setVolumeProvider(volumeProvider);
+        }
+
+        @Override
+        public Builder setRatingType(@Rating2.Style int type) {
+            return super.setRatingType(type);
+        }
+
+        @Override
+        public Builder setSessionActivity(@Nullable PendingIntent pi) {
+            return super.setSessionActivity(pi);
+        }
+
+        @Override
+        public Builder setId(@NonNull String id) {
+            return super.setId(id);
+        }
+
+        @Override
+        public Builder setSessionCallback(@NonNull Executor executor,
+                @Nullable SessionCallback callback) {
+            return super.setSessionCallback(executor, callback);
+        }
+
+        @Override
+        public MediaSession2 build() {
+            return super.build();
+        }
     }
 
     /**
@@ -1035,8 +1078,8 @@
      * If the new player is successfully set, {@link PlaybackListener}
      * will be called to tell the current playback state of the new player.
      * <p>
-     * You can also specify a volume provider. If so, playback in the player is considered as
-     * remote playback.
+     * For the remote playback case which you want to handle volume by yourself, use
+     * {@link #setPlayer(MediaPlayerInterface, VolumeProvider2)}.
      *
      * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
      * @throws IllegalArgumentException if the player is {@code null}.
@@ -1051,10 +1094,10 @@
      * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
      * @param volumeProvider a volume provider
      * @see #setPlayer(MediaPlayerInterface)
-     * @see Builder#setVolumeProvider(VolumeProvider)
+     * @see Builder#setVolumeProvider(VolumeProvider2)
      */
     public void setPlayer(@NonNull MediaPlayerInterface player,
-            @NonNull VolumeProvider volumeProvider) {
+            @NonNull VolumeProvider2 volumeProvider) {
         mProvider.setPlayer_impl(player, volumeProvider);
     }
 
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index 21f9171..131e37b 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -55,7 +55,7 @@
     /**
      * Unknown microphone directionality.
      */
-    public static final int DIRECTIONALITY_UNKNOW = 0;
+    public static final int DIRECTIONALITY_UNKNOWN = 0;
 
     /**
      * Microphone directionality type: omni.
@@ -104,7 +104,7 @@
 
     /** @hide */
     @IntDef(flag = true, prefix = { "DIRECTIONALITY_" }, value = {
-            DIRECTIONALITY_UNKNOW,
+            DIRECTIONALITY_UNKNOWN,
             DIRECTIONALITY_OMNI,
             DIRECTIONALITY_BI_DIRECTIONAL,
             DIRECTIONALITY_CARDIOID,
@@ -309,7 +309,7 @@
 
     /**
      * Returns the directionality of microphone. The return value is one of
-     * {@link #DIRECTIONALITY_UNKNOW}, {@link #DIRECTIONALITY_OMNI},
+     * {@link #DIRECTIONALITY_UNKNOWN}, {@link #DIRECTIONALITY_OMNI},
      * {@link #DIRECTIONALITY_BI_DIRECTIONAL}, {@link #DIRECTIONALITY_CARDIOID},
      * {@link #DIRECTIONALITY_HYPER_CARDIOID}, or {@link #DIRECTIONALITY_SUPER_CARDIOID}.
      *
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
index 00746e2..53ba466 100644
--- a/media/java/android/media/VolumeProvider2.java
+++ b/media/java/android/media/VolumeProvider2.java
@@ -32,7 +32,7 @@
  * {@link #setCurrentVolume(int)} each time the volume being provided changes.
  * <p>
  * You can set a volume provider on a session by calling
- * {@link MediaSession2#setPlayer(MediaPlayerInterface, VolumeProvider)}.
+ * {@link MediaSession2#setPlayer(MediaPlayerInterface, VolumeProvider2)}.
  *
  * @hide
  */
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 0fe7246..f2b4fe0 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -546,22 +546,39 @@
         /**
          * Method called when a new waveform capture is available.
          * <p>Data in the waveform buffer is valid only within the scope of the callback.
-         * Applications which needs access to the waveform data after returning from the callback
+         * Applications which need access to the waveform data after returning from the callback
          * should make a copy of the data instead of holding a reference.
          * @param visualizer Visualizer object on which the listener is registered.
          * @param waveform array of bytes containing the waveform representation.
-         * @param samplingRate sampling rate of the audio visualized.
+         * @param samplingRate sampling rate of the visualized audio.
          */
         void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
 
         /**
          * Method called when a new frequency capture is available.
          * <p>Data in the fft buffer is valid only within the scope of the callback.
-         * Applications which needs access to the fft data after returning from the callback
+         * Applications which need access to the fft data after returning from the callback
          * should make a copy of the data instead of holding a reference.
+         *
+         * <p>In order to obtain magnitude and phase values the following formulas can
+         * be used:
+         *    <pre class="prettyprint">
+         *       for (int i = 0; i &lt; fft.size(); i += 2) {
+         *           float magnitude = (float)Math.hypot(fft[i], fft[i + 1]);
+         *           float phase = (float)Math.atan2(fft[i + 1], fft[i]);
+         *       }</pre>
          * @param visualizer Visualizer object on which the listener is registered.
          * @param fft array of bytes containing the frequency representation.
-         * @param samplingRate sampling rate of the audio visualized.
+         *    The fft array only contains the first half of the actual
+         *    FFT spectrum (frequencies up to Nyquist frequency), exploiting
+         *    the symmetry of the spectrum. For each frequencies bin <code>i</code>:
+         *    <ul>
+         *      <li>the element at index <code>2*i</code> in the array contains
+         *          the real part of a complex number,</li>
+         *      <li>the element at index <code>2*i+1</code> contains the imaginary
+         *          part of the complex number.</li>
+         *    </ul>
+         * @param samplingRate sampling rate of the visualized audio.
          */
         void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
     }
diff --git a/media/java/android/media/update/FrameLayoutHelper.java b/media/java/android/media/update/FrameLayoutHelper.java
deleted file mode 100644
index 983dc70..0000000
--- a/media/java/android/media/update/FrameLayoutHelper.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 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.media.update;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-/**
- * Helper class for connecting the public API to an updatable implementation.
- *
- * @see ViewProvider
- *
- * @hide
- */
-public abstract class FrameLayoutHelper<T extends ViewProvider> extends FrameLayout {
-    /** @hide */
-    final public T mProvider;
-
-    /** @hide */
-    public FrameLayoutHelper(ProviderCreator<T> creator,
-            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-
-        mProvider = creator.createProvider(this, new SuperProvider());
-    }
-
-    /** @hide */
-    // TODO @SystemApi
-    public T getProvider() {
-        return mProvider;
-    }
-
-    @Override
-    public CharSequence getAccessibilityClassName() {
-        return mProvider.getAccessibilityClassName_impl();
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return mProvider.onTouchEvent_impl(ev);
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent ev) {
-        return mProvider.onTrackballEvent_impl(ev);
-    }
-
-    @Override
-    public void onFinishInflate() {
-        mProvider.onFinishInflate_impl();
-    }
-
-    @Override
-    public void setEnabled(boolean enabled) {
-        mProvider.setEnabled_impl(enabled);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        mProvider.onAttachedToWindow_impl();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mProvider.onDetachedFromWindow_impl();
-    }
-
-    /** @hide */
-    public class SuperProvider implements ViewProvider {
-        @Override
-        public CharSequence getAccessibilityClassName_impl() {
-            return FrameLayoutHelper.super.getAccessibilityClassName();
-        }
-
-        @Override
-        public boolean onTouchEvent_impl(MotionEvent ev) {
-            return FrameLayoutHelper.super.onTouchEvent(ev);
-        }
-
-        @Override
-        public boolean onTrackballEvent_impl(MotionEvent ev) {
-            return FrameLayoutHelper.super.onTrackballEvent(ev);
-        }
-
-        @Override
-        public void onFinishInflate_impl() {
-            FrameLayoutHelper.super.onFinishInflate();
-        }
-
-        @Override
-        public void setEnabled_impl(boolean enabled) {
-            FrameLayoutHelper.super.setEnabled(enabled);
-        }
-
-        @Override
-        public void onAttachedToWindow_impl() {
-            FrameLayoutHelper.super.onAttachedToWindow();
-        }
-
-        @Override
-        public void onDetachedFromWindow_impl() {
-            FrameLayoutHelper.super.onDetachedFromWindow();
-        }
-    }
-
-    /** @hide */
-    @FunctionalInterface
-    public interface ProviderCreator<U extends ViewProvider> {
-        U createProvider(FrameLayoutHelper<U> instance, ViewProvider superProvider);
-    }
-}
diff --git a/media/java/android/media/update/MediaControlView2Provider.java b/media/java/android/media/update/MediaControlView2Provider.java
index 95fe363..e155e5f 100644
--- a/media/java/android/media/update/MediaControlView2Provider.java
+++ b/media/java/android/media/update/MediaControlView2Provider.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.media.session.MediaController;
+import android.util.AttributeSet;
 import android.view.View;
 
 /**
@@ -34,12 +35,12 @@
  * @hide
  */
 // TODO @SystemApi
-public interface MediaControlView2Provider extends ViewProvider {
+public interface MediaControlView2Provider extends ViewGroupProvider {
+    void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
+
     void setController_impl(MediaController controller);
-    boolean isShowing_impl();
     void setButtonVisibility_impl(int button, int visibility);
     void requestPlayButtonFocus_impl();
-    void onVisibilityAggregated_impl(boolean isVisible);
     void setTimeout_impl(long timeout);
     long getTimeout_impl();
 }
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 9abf34a..41162e0 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -30,7 +30,7 @@
 import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSession2.SessionCallback;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 
@@ -44,7 +44,7 @@
 public interface MediaSession2Provider extends TransportControlProvider {
     void close_impl();
     void setPlayer_impl(MediaPlayerInterface player);
-    void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider);
+    void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider);
     MediaPlayerInterface getPlayer_impl();
     SessionToken2 getToken_impl();
     List<ControllerInfo> getConnectedControllers_impl();
@@ -116,7 +116,7 @@
     }
 
     interface BuilderBaseProvider<T extends MediaSession2, C extends SessionCallback> {
-        void setVolumeProvider_impl(VolumeProvider volumeProvider);
+        void setVolumeProvider_impl(VolumeProvider2 volumeProvider);
         void setRatingType_impl(int type);
         void setSessionActivity_impl(PendingIntent pi);
         void setId_impl(String id);
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 862a402..57f04cc 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -67,10 +67,11 @@
  * @hide
  */
 public interface StaticProvider {
-    MediaControlView2Provider createMediaControlView2(
-            MediaControlView2 instance, ViewProvider superProvider);
-    VideoView2Provider createVideoView2(
-            VideoView2 instance, ViewProvider superProvider,
+    MediaControlView2Provider createMediaControlView2(MediaControlView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
+            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
+    VideoView2Provider createVideoView2(VideoView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
 
     CommandProvider createMediaSession2Command(MediaSession2.Command instance,
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 10f03d2..7251180 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -16,12 +16,14 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.media.AudioAttributes;
 import android.media.MediaPlayerInterface;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
 import android.net.Uri;
+import android.util.AttributeSet;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
@@ -43,7 +45,9 @@
  * @hide
  */
 // TODO @SystemApi
-public interface VideoView2Provider extends ViewProvider {
+public interface VideoView2Provider extends ViewGroupProvider {
+    void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
+
     void setMediaControlView2_impl(MediaControlView2 mediaControlView);
     MediaController getMediaController_impl();
     MediaControlView2 getMediaControlView2_impl();
@@ -52,6 +56,9 @@
     void setSpeed_impl(float speed);
     void setAudioFocusRequest_impl(int focusGain);
     void setAudioAttributes_impl(AudioAttributes attributes);
+    /**
+     * @hide
+     */
     void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerInterface player);
     // TODO: remove setRouteAttributes_impl with MediaSession.Callback once MediaSession2 is ready.
     void setRouteAttributes_impl(List<String> routeCategories, MediaSession.Callback sessionPlayer);
diff --git a/media/java/android/media/update/ViewGroupHelper.java b/media/java/android/media/update/ViewGroupHelper.java
new file mode 100644
index 0000000..2c4f9b9
--- /dev/null
+++ b/media/java/android/media/update/ViewGroupHelper.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright 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.media.update;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Helper class for connecting the public API to an updatable implementation.
+ *
+ * @see ViewGroupProvider
+ *
+ * @hide
+ */
+public abstract class ViewGroupHelper<T extends ViewGroupProvider> extends ViewGroup {
+    /** @hide */
+    final public T mProvider;
+
+    /** @hide */
+    public ViewGroupHelper(ProviderCreator<T> creator,
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mProvider = creator.createProvider(this, new SuperProvider(),
+                new PrivateProvider());
+    }
+
+    /** @hide */
+    // TODO @SystemApi
+    public T getProvider() {
+        return mProvider;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        mProvider.onAttachedToWindow_impl();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mProvider.onDetachedFromWindow_impl();
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return mProvider.getAccessibilityClassName_impl();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return mProvider.onTouchEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent ev) {
+        return mProvider.onTrackballEvent_impl(ev);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        mProvider.onFinishInflate_impl();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        mProvider.setEnabled_impl(enabled);
+    }
+
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        mProvider.onVisibilityAggregated_impl(isVisible);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mProvider.onLayout_impl(changed, left, top, right, bottom);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mProvider.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected int getSuggestedMinimumWidth() {
+        return mProvider.getSuggestedMinimumWidth_impl();
+    }
+
+    @Override
+    protected int getSuggestedMinimumHeight() {
+        return mProvider.getSuggestedMinimumHeight_impl();
+    }
+
+    // setMeasuredDimension is final
+
+    @Override
+    protected boolean checkLayoutParams(LayoutParams p) {
+        return mProvider.checkLayoutParams_impl(p);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return mProvider.generateDefaultLayoutParams_impl();
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return mProvider.generateLayoutParams_impl(attrs);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(LayoutParams lp) {
+        return mProvider.generateLayoutParams_impl(lp);
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return mProvider.shouldDelayChildPressedState_impl();
+    }
+
+    @Override
+    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+            int parentHeightMeasureSpec, int heightUsed) {
+        mProvider.measureChildWithMargins_impl(child,
+                parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+    }
+
+    /** @hide */
+    public class SuperProvider implements ViewGroupProvider {
+        @Override
+        public CharSequence getAccessibilityClassName_impl() {
+            return ViewGroupHelper.super.getAccessibilityClassName();
+        }
+
+        @Override
+        public boolean onTouchEvent_impl(MotionEvent ev) {
+            return ViewGroupHelper.super.onTouchEvent(ev);
+        }
+
+        @Override
+        public boolean onTrackballEvent_impl(MotionEvent ev) {
+            return ViewGroupHelper.super.onTrackballEvent(ev);
+        }
+
+        @Override
+        public void onFinishInflate_impl() {
+            ViewGroupHelper.super.onFinishInflate();
+        }
+
+        @Override
+        public void setEnabled_impl(boolean enabled) {
+            ViewGroupHelper.super.setEnabled(enabled);
+        }
+
+        @Override
+        public void onAttachedToWindow_impl() {
+            ViewGroupHelper.super.onAttachedToWindow();
+        }
+
+        @Override
+        public void onDetachedFromWindow_impl() {
+            ViewGroupHelper.super.onDetachedFromWindow();
+        }
+
+        @Override
+        public void onVisibilityAggregated_impl(boolean isVisible) {
+            ViewGroupHelper.super.onVisibilityAggregated(isVisible);
+        }
+
+        @Override
+        public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+            // abstract method; no super
+        }
+
+        @Override
+        public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+            ViewGroupHelper.super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        @Override
+        public int getSuggestedMinimumWidth_impl() {
+            return ViewGroupHelper.super.getSuggestedMinimumWidth();
+        }
+
+        @Override
+        public int getSuggestedMinimumHeight_impl() {
+            return ViewGroupHelper.super.getSuggestedMinimumHeight();
+        }
+
+        @Override
+        public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+            ViewGroupHelper.super.setMeasuredDimension(measuredWidth, measuredHeight);
+        }
+
+        @Override
+        public boolean checkLayoutParams_impl(LayoutParams p) {
+            return ViewGroupHelper.super.checkLayoutParams(p);
+        }
+
+        @Override
+        public LayoutParams generateDefaultLayoutParams_impl() {
+            return ViewGroupHelper.super.generateDefaultLayoutParams();
+        }
+
+        @Override
+        public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+            return ViewGroupHelper.super.generateLayoutParams(attrs);
+        }
+
+        @Override
+        public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+            return ViewGroupHelper.super.generateLayoutParams(lp);
+        }
+
+        @Override
+        public boolean shouldDelayChildPressedState_impl() {
+            return ViewGroupHelper.super.shouldDelayChildPressedState();
+        }
+
+        @Override
+        public void measureChildWithMargins_impl(View child,
+                int parentWidthMeasureSpec, int widthUsed,
+                int parentHeightMeasureSpec, int heightUsed) {
+            ViewGroupHelper.super.measureChildWithMargins(child,
+                    parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+        }
+    }
+
+    /** @hide */
+    public class PrivateProvider implements ViewGroupProvider {
+        @Override
+        public CharSequence getAccessibilityClassName_impl() {
+            return ViewGroupHelper.this.getAccessibilityClassName();
+        }
+
+        @Override
+        public boolean onTouchEvent_impl(MotionEvent ev) {
+            return ViewGroupHelper.this.onTouchEvent(ev);
+        }
+
+        @Override
+        public boolean onTrackballEvent_impl(MotionEvent ev) {
+            return ViewGroupHelper.this.onTrackballEvent(ev);
+        }
+
+        @Override
+        public void onFinishInflate_impl() {
+            ViewGroupHelper.this.onFinishInflate();
+        }
+
+        @Override
+        public void setEnabled_impl(boolean enabled) {
+            ViewGroupHelper.this.setEnabled(enabled);
+        }
+
+        @Override
+        public void onAttachedToWindow_impl() {
+            ViewGroupHelper.this.onAttachedToWindow();
+        }
+
+        @Override
+        public void onDetachedFromWindow_impl() {
+            ViewGroupHelper.this.onDetachedFromWindow();
+        }
+
+        @Override
+        public void onVisibilityAggregated_impl(boolean isVisible) {
+            ViewGroupHelper.this.onVisibilityAggregated(isVisible);
+        }
+
+        @Override
+        public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+            ViewGroupHelper.this.onLayout(changed, left, top, right, bottom);
+        }
+
+        @Override
+        public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+            ViewGroupHelper.this.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        @Override
+        public int getSuggestedMinimumWidth_impl() {
+            return ViewGroupHelper.this.getSuggestedMinimumWidth();
+        }
+
+        @Override
+        public int getSuggestedMinimumHeight_impl() {
+            return ViewGroupHelper.this.getSuggestedMinimumHeight();
+        }
+
+        @Override
+        public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+            ViewGroupHelper.this.setMeasuredDimension(measuredWidth, measuredHeight);
+        }
+
+        @Override
+        public boolean checkLayoutParams_impl(LayoutParams p) {
+            return ViewGroupHelper.this.checkLayoutParams(p);
+        }
+
+        @Override
+        public LayoutParams generateDefaultLayoutParams_impl() {
+            return ViewGroupHelper.this.generateDefaultLayoutParams();
+        }
+
+        @Override
+        public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+            return ViewGroupHelper.this.generateLayoutParams(attrs);
+        }
+
+        @Override
+        public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+            return ViewGroupHelper.this.generateLayoutParams(lp);
+        }
+
+        @Override
+        public boolean shouldDelayChildPressedState_impl() {
+            return ViewGroupHelper.this.shouldDelayChildPressedState();
+        }
+
+        @Override
+        public void measureChildWithMargins_impl(View child,
+                int parentWidthMeasureSpec, int widthUsed,
+                int parentHeightMeasureSpec, int heightUsed) {
+            ViewGroupHelper.this.measureChildWithMargins(child,
+                    parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+        }
+    }
+
+        /** @hide */
+    @FunctionalInterface
+    public interface ProviderCreator<T extends ViewGroupProvider> {
+        T createProvider(ViewGroupHelper<T> instance, ViewGroupProvider superProvider,
+                ViewGroupProvider privateProvider);
+    }
+}
diff --git a/media/java/android/media/update/ViewGroupProvider.java b/media/java/android/media/update/ViewGroupProvider.java
new file mode 100644
index 0000000..5f12529
--- /dev/null
+++ b/media/java/android/media/update/ViewGroupProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.media.update;
+
+import android.annotation.SystemApi;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.view.View
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface ViewGroupProvider {
+    // View methods
+    void onAttachedToWindow_impl();
+    void onDetachedFromWindow_impl();
+    CharSequence getAccessibilityClassName_impl();
+    boolean onTouchEvent_impl(MotionEvent ev);
+    boolean onTrackballEvent_impl(MotionEvent ev);
+    void onFinishInflate_impl();
+    void setEnabled_impl(boolean enabled);
+    void onVisibilityAggregated_impl(boolean isVisible);
+    void onLayout_impl(boolean changed, int left, int top, int right, int bottom);
+    void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec);
+    int getSuggestedMinimumWidth_impl();
+    int getSuggestedMinimumHeight_impl();
+    void setMeasuredDimension_impl(int measuredWidth, int measuredHeight);
+
+    // ViewGroup methods
+    boolean checkLayoutParams_impl(LayoutParams p);
+    LayoutParams generateDefaultLayoutParams_impl();
+    LayoutParams generateLayoutParams_impl(AttributeSet attrs);
+    LayoutParams generateLayoutParams_impl(LayoutParams lp);
+    boolean shouldDelayChildPressedState_impl();
+    void measureChildWithMargins_impl(View child, int parentWidthMeasureSpec, int widthUsed,
+        int parentHeightMeasureSpec, int heightUsed);
+
+    // ViewManager methods
+    // ViewParent methods
+}
diff --git a/media/java/android/media/update/ViewProvider.java b/media/java/android/media/update/ViewProvider.java
deleted file mode 100644
index 0dd8f38..0000000
--- a/media/java/android/media/update/ViewProvider.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.update;
-
-import android.annotation.SystemApi;
-import android.view.MotionEvent;
-
-/**
- * Interface for connecting the public API to an updatable implementation.
- *
- * Each instance object is connected to one corresponding updatable object which implements the
- * runtime behavior of that class. There should a corresponding provider method for all public
- * methods.
- *
- * All methods behave as per their namesake in the public API.
- *
- * @see android.view.View
- *
- * @hide
- */
-// TODO @SystemApi
-public interface ViewProvider {
-    // TODO Add more (all?) methods from View
-    void onAttachedToWindow_impl();
-    void onDetachedFromWindow_impl();
-    CharSequence getAccessibilityClassName_impl();
-    boolean onTouchEvent_impl(MotionEvent ev);
-    boolean onTrackballEvent_impl(MotionEvent ev);
-    void onFinishInflate_impl();
-    void setEnabled_impl(boolean enabled);
-}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 90ee8a6..27eaed0 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -19,12 +19,16 @@
 #define LOG_TAG "MediaPlayer2-JNI"
 #include "utils/Log.h"
 
+#include <sys/stat.h>
+
 #include <media/mediaplayer2.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/DataSourceDesc.h>
 #include <media/MediaHTTPService.h>
 #include <media/MediaPlayer2Interface.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/NdkWrapper.h>
+#include <media/stagefright/Utils.h>
 #include <media/stagefright/foundation/ByteUtils.h>  // for FOURCC definition
 #include <stdio.h>
 #include <assert.h>
@@ -234,7 +238,8 @@
 // event to the client application; otherwise, if exception is not NULL and
 // opStatus is not OK, this method throws the given exception to the client
 // application.
-static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
+static void process_media_player_call(
+    JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
 {
     if (exception == NULL) {  // Don't throw exception. Instead, send an event.
         if (opStatus != (status_t) OK) {
@@ -268,7 +273,7 @@
         jobjectArray keys, jobjectArray values) {
 
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
+    if (mp == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
@@ -282,16 +287,25 @@
     if (tmp == NULL) {  // Out of memory
         return;
     }
-    ALOGV("setDataSource: path %s", tmp);
+    ALOGV("setDataSourceAndHeaders: path %s", tmp);
 
-    String8 pathStr(tmp);
+    if (strncmp(tmp, "content://", 10) == 0) {
+        ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
+        jniThrowException(env, "java/io/IOException",
+                          "content scheme is not supported in native code");
+        return;
+    }
+
+    sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mType = DataSourceDesc::TYPE_URL;
+    dsd->mUrl = tmp;
+
     env->ReleaseStringUTFChars(path, tmp);
     tmp = NULL;
 
     // We build a KeyedVector out of the key and val arrays
-    KeyedVector<String8, String8> headersVector;
     if (!ConvertKeyValueArraysToKeyedVector(
-            env, keys, values, &headersVector)) {
+            env, keys, values, &dsd->mHeaders)) {
         return;
     }
 
@@ -299,20 +313,16 @@
     if (httpServiceObj != NULL) {
         httpService = new JMedia2HTTPService(env, httpServiceObj);
     }
-
-    status_t opStatus =
-        mp->setDataSource(
-                httpService,
-                pathStr,
-                headersVector.size() > 0? &headersVector : NULL);
+    dsd->mHttpService = httpService;
 
     process_media_player_call(
-            env, thiz, opStatus, "java/io/IOException",
-            "setDataSource failed." );
+            env, thiz, mp->setDataSource(dsd), "java/io/IOException",
+            "setDataSourceAndHeaders failed." );
 }
 
 static void
-android_media_MediaPlayer2_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaPlayer2_setDataSourceFD(
+    JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -325,12 +335,46 @@
         return;
     }
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    ALOGV("setDataSourceFD: fd %d", fd);
-    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
+    ALOGV("setDataSourceFD: fd=%d (%s), offset=%lld, length=%lld",
+          fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+
+    struct stat sb;
+    int ret = fstat(fd, &sb);
+    if (ret != 0) {
+        ALOGE("setDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+        jniThrowException(env, "java/io/IOException", "setDataSourceFD failed fstat");
+        return;
+    }
+
+    ALOGV("st_dev  = %llu", static_cast<unsigned long long>(sb.st_dev));
+    ALOGV("st_mode = %u", sb.st_mode);
+    ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
+    ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
+    ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
+
+    if (offset >= sb.st_size) {
+        ALOGE("setDataSourceFD: offset is out of range");
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "setDataSourceFD failed, offset is out of range.");
+        return;
+    }
+    if (offset + length > sb.st_size) {
+        length = sb.st_size - offset;
+        ALOGV("setDataSourceFD: adjusted length = %lld", (long long)length);
+    }
+
+    sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mType = DataSourceDesc::TYPE_FD;
+    dsd->mFD = fd;
+    dsd->mFDOffset = offset;
+    dsd->mFDLength = length;
+    process_media_player_call(env, thiz, mp->setDataSource(dsd),
+                              "java/io/IOException", "setDataSourceFD failed." );
 }
 
 static void
-android_media_MediaPlayer2_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
+android_media_MediaPlayer2_setDataSourceCallback(
+    JNIEnv *env, jobject thiz, jobject dataSource)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -343,7 +387,11 @@
         return;
     }
     sp<DataSource> callbackDataSource = new JMedia2DataSource(env, dataSource);
-    process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
+    sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mType = DataSourceDesc::TYPE_CALLBACK;
+    dsd->mCallbackSource = callbackDataSource;
+    process_media_player_call(env, thiz, mp->setDataSource(dsd),
+                              "java/lang/RuntimeException", "setDataSourceCallback failed." );
 }
 
 static sp<ANativeWindowWrapper>
@@ -1099,45 +1147,6 @@
     process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
 }
 
-static jint
-android_media_MediaPlayer2_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
-                                                jstring addrString, jint port) {
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return INVALID_OPERATION;
-    }
-
-    const char *cAddrString = NULL;
-
-    if (NULL != addrString) {
-        cAddrString = env->GetStringUTFChars(addrString, NULL);
-        if (cAddrString == NULL) {  // Out of memory
-            return NO_MEMORY;
-        }
-    }
-    ALOGV("setRetransmitEndpoint: %s:%d",
-            cAddrString ? cAddrString : "(null)", port);
-
-    status_t ret;
-    if (cAddrString && (port > 0xFFFF)) {
-        ret = BAD_VALUE;
-    } else {
-        ret = mp->setRetransmitEndpoint(cAddrString,
-                static_cast<uint16_t>(port));
-    }
-
-    if (NULL != addrString) {
-        env->ReleaseStringUTFChars(addrString, cAddrString);
-    }
-
-    if (ret == INVALID_OPERATION ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-    }
-
-    return (jint) ret;
-}
-
 static void
 android_media_MediaPlayer2_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
 {
@@ -1418,7 +1427,6 @@
     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer2_set_audio_session_id},
     {"_setAuxEffectSendLevel", "(F)V",                          (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer2_attachAuxEffect},
-    {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer2_setRetransmitEndpoint},
     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer2;)V",  (void *)android_media_MediaPlayer2_setNextMediaPlayer},
     // Modular DRM
     { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer2_prepareDrm },
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 00fe638..4fb5e74 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -48,6 +48,7 @@
         "sensor.cpp",
         "sharedmem.cpp",
         "storage_manager.cpp",
+        "surface_texture.cpp",
         "trace.cpp",
     ],
 
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 3d5ee39..d6dcd72 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,14 @@
     AStorageManager_mountObb;
     AStorageManager_new;
     AStorageManager_unmountObb;
+    ASurfaceTexture_acquireANativeWindow; # introduced=28
+    ASurfaceTexture_attachToGLContext; # introduced=28
+    ASurfaceTexture_detachFromGLContext; # introduced=28
+    ASurfaceTexture_fromSurfaceTexture; # introduced=28
+    ASurfaceTexture_getTimestamp; # introduced=28
+    ASurfaceTexture_getTransformMatrix; # introduced=28
+    ASurfaceTexture_release; # introduced=28
+    ASurfaceTexture_updateTexImage; # introduced=28
     ATrace_beginSection; # introduced=23
     ATrace_endSection; # introduced=23
     ATrace_isEnabled; # introduced=23
diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
new file mode 100644
index 0000000..b266881
--- /dev/null
+++ b/native/android/surface_texture.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include <android/surface_texture.h>
+#include <android/surface_texture_jni.h>
+
+#define LOG_TAG "ASurfaceTexture"
+
+#include <utils/Log.h>
+
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
+
+#include <android_runtime/android_graphics_SurfaceTexture.h>
+
+using namespace android;
+
+struct ASurfaceTexture {
+    sp<GLConsumer> consumer;
+    sp<IGraphicBufferProducer> producer;
+};
+
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+    if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
+        return nullptr;
+    }
+    ASurfaceTexture* ast = new ASurfaceTexture;
+    ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
+    ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
+    return ast;
+}
+
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
+    sp<Surface> surface = new Surface(st->producer);
+    ANativeWindow* win(surface.get());
+    ANativeWindow_acquire(win);
+    return win;
+}
+
+void ASurfaceTexture_release(ASurfaceTexture* st) {
+    delete st;
+}
+
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) {
+    return st->consumer->attachToContext(tex);
+}
+
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
+    return st->consumer->detachFromContext();
+}
+
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
+    return st->consumer->updateTexImage();
+}
+
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+    st->consumer->getTransformMatrix(mtx);
+}
+
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
+    return st->consumer->getTimestamp();
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 6fe8975..9a66b07 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -94,7 +94,7 @@
                 infile = mFile.openRead();
                 readXml(infile);
             } catch (FileNotFoundException e) {
-                // No data yet
+                Log.d(TAG, "File doesn't exist or isn't readable yet");
             } catch (IOException e) {
                 Log.e(TAG, "Unable to read channel impressions", e);
             } catch (NumberFormatException | XmlPullParserException e) {
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
index 7c35b48..db48f61 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
@@ -325,7 +325,8 @@
         int dismiss2 = 777;
         String key2 = mAssistant.getKey("pkg2", 2, "channel2");
 
-        String xml = "<assistant version=\"1\">\n"
+        String xml = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                + "<assistant version=\"1\">\n"
                 + "<impression-set key=\"" + key1 + "\" "
                 + "dismisses=\"" + dismiss1 + "\" views=\"" + views1
                 + "\" streak=\"" + streak1 + "\"/>\n"
@@ -377,7 +378,6 @@
         mAssistant.insertImpressions(key2, ci2);
         mAssistant.insertImpressions(key3, ci3);
 
-
         XmlSerializer serializer = new FastXmlSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e11017c..f699440 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -622,6 +622,19 @@
         return builder.toString();
     }
 
+    public static String getKey(WifiConfiguration config) {
+        StringBuilder builder = new StringBuilder();
+
+        if (TextUtils.isEmpty(config.SSID)) {
+            builder.append(config.BSSID);
+        } else {
+            builder.append(removeDoubleQuotes(config.SSID));
+        }
+
+        builder.append(',').append(getSecurity(config));
+        return builder.toString();
+    }
+
     public String getKey() {
         return mKey;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 1ac56a9..fac585e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -92,8 +92,6 @@
      * and used so as to assist with in-the-field WiFi connectivity debugging  */
     public static boolean sVerboseLogging;
 
-    // TODO(b/36733768): Remove flag includeSaved
-
     // TODO: Allow control of this?
     // Combo scans can take 5-6s to complete - set to 10s.
     private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
@@ -106,8 +104,6 @@
     private final NetworkRequest mNetworkRequest;
     private final AtomicBoolean mConnected = new AtomicBoolean(false);
     private final WifiListener mListener;
-    private final boolean mIncludeSaved;
-    private final boolean mIncludeScans;
     @VisibleForTesting MainHandler mMainHandler;
     @VisibleForTesting WorkHandler mWorkHandler;
     private HandlerThread mWorkThread;
@@ -150,7 +146,6 @@
 
     // TODO(sghuman): Change this to be keyed on AccessPoint.getKey
     private final HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
-    private Integer mScanId = 0;
 
     private NetworkInfo mLastNetworkInfo;
     private WifiInfo mLastInfo;
@@ -189,16 +184,18 @@
     @Deprecated
     public WifiTracker(Context context, WifiListener wifiListener,
             boolean includeSaved, boolean includeScans) {
-        this(context, wifiListener, includeSaved, includeScans,
+        this(context, wifiListener,
                 context.getSystemService(WifiManager.class),
                 context.getSystemService(ConnectivityManager.class),
                 context.getSystemService(NetworkScoreManager.class),
                 newIntentFilter());
     }
 
+    // TODO(Sghuman): Clean up includeSaved and includeScans from all constructors and linked
+    // calling apps once IC window is complete
     public WifiTracker(Context context, WifiListener wifiListener,
             @NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
-        this(context, wifiListener, includeSaved, includeScans,
+        this(context, wifiListener,
                 context.getSystemService(WifiManager.class),
                 context.getSystemService(ConnectivityManager.class),
                 context.getSystemService(NetworkScoreManager.class),
@@ -208,19 +205,13 @@
 
     @VisibleForTesting
     WifiTracker(Context context, WifiListener wifiListener,
-            boolean includeSaved, boolean includeScans,
             WifiManager wifiManager, ConnectivityManager connectivityManager,
             NetworkScoreManager networkScoreManager,
             IntentFilter filter) {
-        if (!includeSaved && !includeScans) {
-            throw new IllegalArgumentException("Must include either saved or scans");
-        }
         mContext = context;
         mMainHandler = new MainHandler(Looper.getMainLooper());
         mWifiManager = wifiManager;
-        mIncludeSaved = includeSaved;
-        mIncludeScans = includeScans;
-        mListener = wifiListener;
+        mListener = new WifiListenerWrapper(wifiListener);
         mConnectivityManager = connectivityManager;
 
         // check if verbose logging has been turned on or off
@@ -458,7 +449,6 @@
     private void handleResume() {
         mScanResultCache.clear();
         mSeenBssids.clear();
-        mScanId = 0;
     }
 
     private Collection<ScanResult> updateScanResultCache(final List<ScanResult> newResults) {
@@ -533,7 +523,7 @@
     /**
      * Update the internal list of access points.
      *
-     * <p>Do not called directly (except for forceUpdate), use {@link #updateAccessPoints()} which
+     * <p>Do not call directly (except for forceUpdate), use {@link #updateAccessPoints()} which
      * respects {@link #mStaleScanResults}.
      */
     @GuardedBy("mLock")
@@ -542,7 +532,7 @@
         WifiConfiguration connectionConfig = null;
         if (mLastInfo != null) {
             connectionConfig = getWifiConfigurationForNetworkId(
-                    mLastInfo.getNetworkId(), mWifiManager.getConfiguredNetworks());
+                    mLastInfo.getNetworkId(), configs);
         }
 
         // Swap the current access points into a cached list.
@@ -554,43 +544,12 @@
             accessPoint.clearConfig();
         }
 
-    /* Lookup table to more quickly update AccessPoints by only considering objects with the
-     * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
-        Multimap<String, AccessPoint> existingApMap = new Multimap<String, AccessPoint>();
-
         final Collection<ScanResult> results = updateScanResultCache(newScanResults);
 
-        // TODO(sghuman): This entire block only exists to populate the WifiConfiguration for
-        // APs, remove and refactor
+        final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
         if (configs != null) {
             for (WifiConfiguration config : configs) {
-                if (config.selfAdded && config.numAssociation == 0) {
-                    continue;
-                }
-                AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
-                if (mLastInfo != null && mLastNetworkInfo != null) {
-                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                }
-                if (mIncludeSaved) {
-                    // If saved network not present in scan result then set its Rssi to
-                    // UNREACHABLE_RSSI
-                    boolean apFound = false;
-                    for (ScanResult result : results) {
-                        if (result.SSID.equals(accessPoint.getSsidStr())) {
-                            apFound = true;
-                            break;
-                        }
-                    }
-                    if (!apFound) {
-                        accessPoint.setUnreachable();
-                    }
-                    accessPoints.add(accessPoint);
-                    existingApMap.put(accessPoint.getSsidStr(), accessPoint);
-                } else {
-                    // If we aren't using saved networks, drop them into the cache so that
-                    // we have access to their saved info.
-                    cachedAccessPoints.add(accessPoint);
-                }
+                configsByKey.put(AccessPoint.getKey(config), config);
             }
         }
 
@@ -626,40 +585,20 @@
             for (Map.Entry<String, List<ScanResult>> entry : scanResultsByApKey.entrySet()) {
                 // List can not be empty as it is dynamically constructed on each iteration
                 ScanResult firstResult = entry.getValue().get(0);
-                boolean found = false;
-                for (AccessPoint accessPoint : existingApMap.getAll(firstResult.SSID)) {
-                    accessPoint.setScanResults(entry.getValue());
-                    found = true;
-                    break;
+
+                AccessPoint accessPoint =
+                        getCachedOrCreate(entry.getValue(), cachedAccessPoints);
+                if (mLastInfo != null && mLastNetworkInfo != null) {
+                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                 }
 
-                // Only create a new AP / add to the list if it wasn't already in the saved configs
-                if (!found) {
-                    AccessPoint accessPoint =
-                            getCachedOrCreate(entry.getValue(), cachedAccessPoints);
-                    if (mLastInfo != null && mLastNetworkInfo != null) {
-                        accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                    }
-
-                    // TODO(sghuman): Move isPasspointNetwork logic into AccessPoint.java
-                    if (firstResult.isPasspointNetwork()) {
-                        // Retrieve a WifiConfiguration for a Passpoint provider that matches
-                        // the given ScanResult.  This is used for showing that a given AP
-                        // (ScanResult) is available via a Passpoint provider (provider friendly
-                        // name).
-                        try {
-                            WifiConfiguration config =
-                                    mWifiManager.getMatchingWifiConfig(firstResult);
-                            if (config != null) {
-                                accessPoint.update(config);
-                            }
-                        } catch (UnsupportedOperationException e) {
-                            // Passpoint not supported on the device.
-                        }
-                    }
-
-                    accessPoints.add(accessPoint);
+                // Update the matching config if there is one, to populate saved network info
+                WifiConfiguration config = configsByKey.get(entry.getKey());
+                if (config != null) {
+                    accessPoint.update(config);
                 }
+
+                accessPoints.add(accessPoint);
             }
         }
 
@@ -1052,6 +991,39 @@
         }
     }
 
+    /**
+     * Wraps the given {@link WifiListener} instance and executes it's methods on the Main Thread.
+     *
+     * <p>This mechanism allows us to no longer need a separate MainHandler and WorkHandler, which
+     * were previously both performing work, while avoiding errors which occur from executing
+     * callbacks which manipulate UI elements from a different thread than the MainThread.
+     */
+    private static class WifiListenerWrapper implements WifiListener {
+
+        private final Handler mHandler;
+        private final WifiListener mDelegatee;
+
+        public WifiListenerWrapper(WifiListener listener) {
+            mHandler = new Handler(Looper.getMainLooper());
+            mDelegatee = listener;
+        }
+
+        @Override
+        public void onWifiStateChanged(int state) {
+            mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
+        }
+
+        @Override
+        public void onConnectedChanged() {
+            mHandler.post(() -> mDelegatee.onConnectedChanged());
+        }
+
+        @Override
+        public void onAccessPointsChanged() {
+            mHandler.post(() -> mDelegatee.onAccessPointsChanged());
+        }
+    }
+
     public interface WifiListener {
         /**
          * Called when the state of Wifi has changed, the state will be one of
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index b36dda9..6be4936 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -281,8 +281,6 @@
         final WifiTracker wifiTracker = new WifiTracker(
                 mContext,
                 mockWifiListener,
-                true,
-                true,
                 mockWifiManager,
                 mockConnectivityManager,
                 mockNetworkScoreManager,
@@ -687,6 +685,7 @@
      */
     @Test
     public void trackPasspointApWithPasspointDisabled() throws Exception {
+        // TODO(sghuman): Delete this test and replace with a passpoint test
         WifiTracker tracker = createMockedWifiTracker();
 
         // Add a Passpoint AP to the scan results.
@@ -709,10 +708,7 @@
         when(mockWifiManager.getConfiguredNetworks())
                 .thenReturn(new ArrayList<WifiConfiguration>());
         when(mockWifiManager.getScanResults()).thenReturn(results);
-        doThrow(new UnsupportedOperationException())
-                .when(mockWifiManager).getMatchingWifiConfig(any(ScanResult.class));
         tracker.forceUpdate();
-        verify(mockWifiManager).getMatchingWifiConfig(any(ScanResult.class));
     }
 
     @Test
@@ -758,7 +754,7 @@
         tracker.forceUpdate();
 
         verify(mockWifiManager).getConnectionInfo();
-        verify(mockWifiManager, times(2)).getConfiguredNetworks();
+        verify(mockWifiManager, times(1)).getConfiguredNetworks();
         verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
 
         verify(mockWifiListener, never()).onAccessPointsChanged(); // mStaleAccessPoints is true
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b286f89..537e8dc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -523,9 +523,6 @@
                 Settings.Global.WIFI_WAKEUP_ENABLED,
                 GlobalSettingsProto.WIFI_WAKEUP_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.WIFI_WAKEUP_AVAILABLE,
-                GlobalSettingsProto.WIFI_WAKEUP_AVAILABLE);
-        dumpSetting(s, p,
                 Settings.Global.NETWORK_SCORING_UI_ENABLED,
                 GlobalSettingsProto.NETWORK_SCORING_UI_ENABLED);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d1459bb..adb4dbf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2328,7 +2328,9 @@
                     // Get all uids for the user's packages.
                     final List<PackageInfo> packages;
                     try {
-                        packages = mPackageManager.getInstalledPackages(0, user.id).getList();
+                        packages = mPackageManager.getInstalledPackages(
+                            PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                            user.id).getList();
                     } catch (RemoteException e) {
                         throw new IllegalStateException("Package manager not available");
                     }
@@ -3015,7 +3017,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 152;
+            private static final int SETTINGS_VERSION = 153;
 
             private final int mUserId;
 
@@ -3401,7 +3403,9 @@
                         // Fill each uid with the legacy ssaid to be backwards compatible.
                         final List<PackageInfo> packages;
                         try {
-                            packages = mPackageManager.getInstalledPackages(0, userId).getList();
+                            packages = mPackageManager.getInstalledPackages(
+                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                                userId).getList();
                         } catch (RemoteException e) {
                             throw new IllegalStateException("Package manager not available");
                         }
@@ -3416,6 +3420,9 @@
                                 // Android Id doesn't exist for this package so create it.
                                 ssaidSettings.insertSettingLocked(uid, legacySsaid, null, true,
                                         info.packageName);
+                                if (DEBUG) {
+                                    Slog.d(LOG_TAG, "Keep the legacy ssaid for uid=" + uid);
+                                }
                             }
                         }
                     }
@@ -3540,21 +3547,9 @@
                 }
 
                 if (currentVersion == 146) {
-                    // Version 147: Set the default value for WIFI_WAKEUP_AVAILABLE.
-                    if (userId == UserHandle.USER_SYSTEM) {
-                        final SettingsState globalSettings = getGlobalSettingsLocked();
-                        final Setting currentSetting = globalSettings.getSettingLocked(
-                                Settings.Global.WIFI_WAKEUP_AVAILABLE);
-                        if (currentSetting.getValue() == null) {
-                            final int defaultValue = getContext().getResources().getInteger(
-                                    com.android.internal.R.integer.config_wifi_wakeup_available);
-                            globalSettings.insertSettingLocked(
-                                    Settings.Global.WIFI_WAKEUP_AVAILABLE,
-                                    String.valueOf(defaultValue),
-                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
-                        }
-                    }
-
+                    // Version 147: Removed. (This version previously allowed showing the
+                    // "wifi_wakeup_available" setting).
+                    // The setting that was added here is deleted in 153.
                     currentVersion = 147;
                 }
 
@@ -3621,18 +3616,17 @@
                 }
 
                 if (currentVersion == 151) {
-                    // Version 152: Reset wifi wake available for upgrading users
-                    final SettingsState globalSettings = getGlobalSettingsLocked();
-                    final int defaultValue = getContext().getResources().getInteger(
-                            com.android.internal.R.integer.config_wifi_wakeup_available);
-                    globalSettings.insertSettingLocked(
-                            Settings.Global.WIFI_WAKEUP_AVAILABLE,
-                            String.valueOf(defaultValue),
-                            null, true, SettingsState.SYSTEM_PACKAGE_NAME);
-
+                    // Version 152: Removed. (This version made the setting for wifi_wakeup enabled
+                    // by default but it is now no longer configurable).
+                    // The setting updated here is deleted in 153.
                     currentVersion = 152;
                 }
 
+                if (currentVersion == 152) {
+                    getGlobalSettingsLocked().deleteSettingLocked("wifi_wakeup_available");
+                    currentVersion = 153;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index c2b1009..a3118b0 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -84,7 +84,25 @@
         android:layout_height="@dimen/screen_pinning_request_button_height"
         android:layout_weight="0"
         android:paddingStart="@dimen/screen_pinning_request_frame_padding"
-        android:paddingEnd="@dimen/screen_pinning_request_frame_padding" >
+        android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
+        android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg_light"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="matrix"
+            android:src="@drawable/screen_pinning_light_bg_circ" />
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingEnd="@dimen/screen_pinning_request_inner_padding"
+            android:paddingStart="@dimen/screen_pinning_request_inner_padding"
+            android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+            android:scaleType="matrix"
+            android:src="@drawable/screen_pinning_bg_circ" />
 
         <ImageView
             android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index b5ef1d7..61fe906 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -78,7 +78,25 @@
         android:id="@+id/screen_pinning_home_group"
         android:layout_height="@dimen/screen_pinning_request_button_width"
         android:layout_width="@dimen/screen_pinning_request_button_height"
-        android:layout_weight="0" >
+        android:layout_weight="0"
+        android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg_light"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            android:scaleType="matrix"
+            android:src="@drawable/screen_pinning_light_bg_circ" />
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            android:scaleType="matrix"
+            android:paddingLeft="@dimen/screen_pinning_request_inner_padding"
+            android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+            android:paddingBottom="@dimen/screen_pinning_request_inner_padding"
+            android:src="@drawable/screen_pinning_bg_circ" />
 
         <ImageView
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
index f3a6d44..d1ca2ce 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
@@ -80,7 +80,27 @@
         android:id="@+id/screen_pinning_home_group"
         android:layout_height="@dimen/screen_pinning_request_button_width"
         android:layout_width="@dimen/screen_pinning_request_button_height"
-        android:layout_weight="0" >
+        android:layout_weight="0"
+        android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent" >
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg_light"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            android:scaleType="matrix"
+            android:layout_marginLeft="@dimen/screen_pinning_request_seascape_padding_negative"
+            android:src="@drawable/screen_pinning_light_bg_circ" />
+
+        <ImageView
+            android:id="@+id/screen_pinning_home_bg"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            android:scaleType="matrix"
+            android:layout_marginLeft="@dimen/screen_pinning_request_seascape_button_offset"
+            android:paddingRight="@dimen/screen_pinning_request_inner_padding"
+            android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+            android:paddingBottom="@dimen/screen_pinning_request_inner_padding"
+            android:src="@drawable/screen_pinning_bg_circ" />
 
         <ImageView
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 53dff05..36298ca 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -20,14 +20,15 @@
     android:background="@android:color/transparent"
     android:theme="@style/qs_theme"
     android:clipChildren="false" >
+    <!-- right-aligned to be physically near volume button -->
     <LinearLayout
         android:id="@+id/volume_dialog"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|end"
+        android:layout_gravity="center_vertical|right"
         android:minWidth="@dimen/volume_dialog_panel_width"
         android:background="@android:color/transparent"
-        android:layout_margin="12dp"
+        android:layout_margin="@dimen/volume_dialog_base_margin"
         android:translationZ="8dp"
         android:orientation="vertical"
         android:clipChildren="false" >
@@ -38,8 +39,8 @@
             android:layout_height="wrap_content"
             android:clipChildren="false"
             android:clipToPadding="false"
-            android:paddingTop="12dp"
-            android:paddingBottom="12dp"
+            android:paddingTop="10dp"
+            android:paddingBottom="10dp"
             android:background="@drawable/rounded_bg_full"
             android:translationZ="8dp"
             android:orientation="horizontal" >
@@ -71,7 +72,7 @@
                 android:maxLines="1"
                 android:layout_centerVertical="true"
                 android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="?android:attr/textAppearanceSmall" />
+                android:textAppearance="@style/TextAppearance.Volume.Header" />
 
             <com.android.keyguard.AlphaOptimizedImageButton
                 android:id="@+id/ringer_icon"
@@ -89,7 +90,7 @@
                 android:ellipsize="end"
                 android:maxLines="1"
                 android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="?android:attr/textAppearanceSmall" />
+                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
 
         </LinearLayout>
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index a9e5adf..70654a8 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -29,15 +29,16 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="center"
-        android:padding="10dp">
+        android:padding="5dp">
         <TextView
             android:id="@+id/volume_row_header"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:ellipsize="end"
+            android:maxLength="10"
             android:maxLines="1"
             android:textColor="?android:attr/colorControlNormal"
-            android:textAppearance="?android:attr/textAppearanceSmall" />
+            android:textAppearance="@style/TextAppearance.Volume.Header" />
         <LinearLayout
             android:id="@+id/output_chooser"
             android:orientation="vertical"
@@ -53,9 +54,10 @@
                 android:visibility="gone"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:maxLength="10"
                 android:ellipsize="end"
                 android:maxLines="1"
-                android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
+                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
             <com.android.keyguard.AlphaOptimizedImageButton
                 android:id="@+id/output_chooser_button"
                 android:layout_width="24dp"
@@ -73,15 +75,18 @@
         android:id="@+id/volume_row_slider_frame"
         android:padding="0dp"
         android:layout_width="@dimen/volume_dialog_panel_width"
-        android:layout_height="150dp">
+        android:layoutDirection="rtl"
+        android:layout_height="@dimen/volume_dialog_panel_width">
         <SeekBar
             android:id="@+id/volume_row_slider"
+            android:clickable="true"
             android:padding="0dp"
             android:layout_margin="0dp"
-            android:layout_width="150dp"
+            android:layout_width="@dimen/volume_dialog_panel_width"
             android:layout_height="@dimen/volume_dialog_panel_width"
+            android:layoutDirection="rtl"
             android:layout_gravity="center"
-            android:rotation="270" />
+            android:rotation="90" />
     </FrameLayout>
 
     <com.android.keyguard.AlphaOptimizedImageButton
diff --git a/packages/SystemUI/res/values-af/config.xml b/packages/SystemUI/res/values-af/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-af/config.xml
+++ b/packages/SystemUI/res/values-af/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/config.xml b/packages/SystemUI/res/values-am/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-am/config.xml
+++ b/packages/SystemUI/res/values-am/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/config.xml b/packages/SystemUI/res/values-ar/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ar/config.xml
+++ b/packages/SystemUI/res/values-ar/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/config.xml b/packages/SystemUI/res/values-az/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-az/config.xml
+++ b/packages/SystemUI/res/values-az/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/config.xml b/packages/SystemUI/res/values-b+sr+Latn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/config.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/config.xml b/packages/SystemUI/res/values-be/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-be/config.xml
+++ b/packages/SystemUI/res/values-be/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/config.xml b/packages/SystemUI/res/values-bg/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bg/config.xml
+++ b/packages/SystemUI/res/values-bg/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/config.xml b/packages/SystemUI/res/values-bn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bn/config.xml
+++ b/packages/SystemUI/res/values-bn/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/config.xml b/packages/SystemUI/res/values-bs/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bs/config.xml
+++ b/packages/SystemUI/res/values-bs/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/config.xml b/packages/SystemUI/res/values-ca/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ca/config.xml
+++ b/packages/SystemUI/res/values-ca/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/config.xml b/packages/SystemUI/res/values-cs/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-cs/config.xml
+++ b/packages/SystemUI/res/values-cs/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/config.xml b/packages/SystemUI/res/values-da/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-da/config.xml
+++ b/packages/SystemUI/res/values-da/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/config.xml b/packages/SystemUI/res/values-de/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-de/config.xml
+++ b/packages/SystemUI/res/values-de/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/config.xml b/packages/SystemUI/res/values-el/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-el/config.xml
+++ b/packages/SystemUI/res/values-el/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/config.xml b/packages/SystemUI/res/values-en-rAU/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rAU/config.xml
+++ b/packages/SystemUI/res/values-en-rAU/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/config.xml b/packages/SystemUI/res/values-en-rCA/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rCA/config.xml
+++ b/packages/SystemUI/res/values-en-rCA/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/config.xml b/packages/SystemUI/res/values-en-rGB/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rGB/config.xml
+++ b/packages/SystemUI/res/values-en-rGB/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/config.xml b/packages/SystemUI/res/values-en-rIN/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rIN/config.xml
+++ b/packages/SystemUI/res/values-en-rIN/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/config.xml b/packages/SystemUI/res/values-en-rXC/config.xml
index f015d9b..5309563 100644
--- a/packages/SystemUI/res/values-en-rXC/config.xml
+++ b/packages/SystemUI/res/values-en-rXC/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎com.android.launcher3/com.android.quickstep.TouchInteractionService‎‏‎‎‏‎"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/config.xml b/packages/SystemUI/res/values-es-rUS/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-es-rUS/config.xml
+++ b/packages/SystemUI/res/values-es-rUS/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/config.xml b/packages/SystemUI/res/values-es/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-es/config.xml
+++ b/packages/SystemUI/res/values-es/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/config.xml b/packages/SystemUI/res/values-et/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-et/config.xml
+++ b/packages/SystemUI/res/values-et/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/config.xml b/packages/SystemUI/res/values-eu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-eu/config.xml
+++ b/packages/SystemUI/res/values-eu/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/config.xml b/packages/SystemUI/res/values-fa/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fa/config.xml
+++ b/packages/SystemUI/res/values-fa/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/config.xml b/packages/SystemUI/res/values-fi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fi/config.xml
+++ b/packages/SystemUI/res/values-fi/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/config.xml b/packages/SystemUI/res/values-fr-rCA/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fr-rCA/config.xml
+++ b/packages/SystemUI/res/values-fr-rCA/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/config.xml b/packages/SystemUI/res/values-fr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fr/config.xml
+++ b/packages/SystemUI/res/values-fr/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/config.xml b/packages/SystemUI/res/values-gl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-gl/config.xml
+++ b/packages/SystemUI/res/values-gl/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/config.xml b/packages/SystemUI/res/values-gu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-gu/config.xml
+++ b/packages/SystemUI/res/values-gu/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/config.xml b/packages/SystemUI/res/values-hi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hi/config.xml
+++ b/packages/SystemUI/res/values-hi/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/config.xml b/packages/SystemUI/res/values-hr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hr/config.xml
+++ b/packages/SystemUI/res/values-hr/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/config.xml b/packages/SystemUI/res/values-hu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hu/config.xml
+++ b/packages/SystemUI/res/values-hu/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/config.xml b/packages/SystemUI/res/values-hy/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hy/config.xml
+++ b/packages/SystemUI/res/values-hy/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/config.xml b/packages/SystemUI/res/values-in/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-in/config.xml
+++ b/packages/SystemUI/res/values-in/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/config.xml b/packages/SystemUI/res/values-is/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-is/config.xml
+++ b/packages/SystemUI/res/values-is/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/config.xml b/packages/SystemUI/res/values-it/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-it/config.xml
+++ b/packages/SystemUI/res/values-it/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/config.xml b/packages/SystemUI/res/values-iw/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-iw/config.xml
+++ b/packages/SystemUI/res/values-iw/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/config.xml b/packages/SystemUI/res/values-ja/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ja/config.xml
+++ b/packages/SystemUI/res/values-ja/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/config.xml b/packages/SystemUI/res/values-ka/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ka/config.xml
+++ b/packages/SystemUI/res/values-ka/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/config.xml b/packages/SystemUI/res/values-kk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-kk/config.xml
+++ b/packages/SystemUI/res/values-kk/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/config.xml b/packages/SystemUI/res/values-km/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-km/config.xml
+++ b/packages/SystemUI/res/values-km/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/config.xml b/packages/SystemUI/res/values-kn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-kn/config.xml
+++ b/packages/SystemUI/res/values-kn/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/config.xml b/packages/SystemUI/res/values-ko/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ko/config.xml
+++ b/packages/SystemUI/res/values-ko/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/config.xml b/packages/SystemUI/res/values-ky/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ky/config.xml
+++ b/packages/SystemUI/res/values-ky/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/config.xml b/packages/SystemUI/res/values-lo/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lo/config.xml
+++ b/packages/SystemUI/res/values-lo/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/config.xml b/packages/SystemUI/res/values-lt/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lt/config.xml
+++ b/packages/SystemUI/res/values-lt/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/config.xml b/packages/SystemUI/res/values-lv/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lv/config.xml
+++ b/packages/SystemUI/res/values-lv/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/config.xml b/packages/SystemUI/res/values-mk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mk/config.xml
+++ b/packages/SystemUI/res/values-mk/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/config.xml b/packages/SystemUI/res/values-ml/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ml/config.xml
+++ b/packages/SystemUI/res/values-ml/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/config.xml b/packages/SystemUI/res/values-mn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mn/config.xml
+++ b/packages/SystemUI/res/values-mn/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/config.xml b/packages/SystemUI/res/values-mr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mr/config.xml
+++ b/packages/SystemUI/res/values-mr/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/config.xml b/packages/SystemUI/res/values-ms/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ms/config.xml
+++ b/packages/SystemUI/res/values-ms/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/config.xml b/packages/SystemUI/res/values-my/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-my/config.xml
+++ b/packages/SystemUI/res/values-my/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/config.xml b/packages/SystemUI/res/values-nb/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-nb/config.xml
+++ b/packages/SystemUI/res/values-nb/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/config.xml b/packages/SystemUI/res/values-ne/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ne/config.xml
+++ b/packages/SystemUI/res/values-ne/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/config.xml b/packages/SystemUI/res/values-nl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-nl/config.xml
+++ b/packages/SystemUI/res/values-nl/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/config.xml b/packages/SystemUI/res/values-pa/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pa/config.xml
+++ b/packages/SystemUI/res/values-pa/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/config.xml b/packages/SystemUI/res/values-pl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pl/config.xml
+++ b/packages/SystemUI/res/values-pl/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/config.xml b/packages/SystemUI/res/values-pt-rBR/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt-rBR/config.xml
+++ b/packages/SystemUI/res/values-pt-rBR/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/config.xml b/packages/SystemUI/res/values-pt-rPT/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt-rPT/config.xml
+++ b/packages/SystemUI/res/values-pt-rPT/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/config.xml b/packages/SystemUI/res/values-pt/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt/config.xml
+++ b/packages/SystemUI/res/values-pt/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/config.xml b/packages/SystemUI/res/values-ro/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ro/config.xml
+++ b/packages/SystemUI/res/values-ro/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/config.xml b/packages/SystemUI/res/values-ru/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ru/config.xml
+++ b/packages/SystemUI/res/values-ru/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/config.xml b/packages/SystemUI/res/values-si/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-si/config.xml
+++ b/packages/SystemUI/res/values-si/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/config.xml b/packages/SystemUI/res/values-sk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sk/config.xml
+++ b/packages/SystemUI/res/values-sk/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/config.xml b/packages/SystemUI/res/values-sl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sl/config.xml
+++ b/packages/SystemUI/res/values-sl/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/config.xml b/packages/SystemUI/res/values-sq/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sq/config.xml
+++ b/packages/SystemUI/res/values-sq/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/config.xml b/packages/SystemUI/res/values-sr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sr/config.xml
+++ b/packages/SystemUI/res/values-sr/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/config.xml b/packages/SystemUI/res/values-sv/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sv/config.xml
+++ b/packages/SystemUI/res/values-sv/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/config.xml b/packages/SystemUI/res/values-sw/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sw/config.xml
+++ b/packages/SystemUI/res/values-sw/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/config.xml b/packages/SystemUI/res/values-ta/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ta/config.xml
+++ b/packages/SystemUI/res/values-ta/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/config.xml b/packages/SystemUI/res/values-te/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-te/config.xml
+++ b/packages/SystemUI/res/values-te/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/config.xml b/packages/SystemUI/res/values-th/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-th/config.xml
+++ b/packages/SystemUI/res/values-th/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/config.xml b/packages/SystemUI/res/values-tl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-tl/config.xml
+++ b/packages/SystemUI/res/values-tl/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/config.xml b/packages/SystemUI/res/values-tr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-tr/config.xml
+++ b/packages/SystemUI/res/values-tr/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/config.xml b/packages/SystemUI/res/values-uk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-uk/config.xml
+++ b/packages/SystemUI/res/values-uk/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/config.xml b/packages/SystemUI/res/values-ur/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ur/config.xml
+++ b/packages/SystemUI/res/values-ur/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/config.xml b/packages/SystemUI/res/values-uz/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-uz/config.xml
+++ b/packages/SystemUI/res/values-uz/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/config.xml b/packages/SystemUI/res/values-vi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-vi/config.xml
+++ b/packages/SystemUI/res/values-vi/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/config.xml b/packages/SystemUI/res/values-zh-rCN/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rCN/config.xml
+++ b/packages/SystemUI/res/values-zh-rCN/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/config.xml b/packages/SystemUI/res/values-zh-rHK/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rHK/config.xml
+++ b/packages/SystemUI/res/values-zh-rHK/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/config.xml b/packages/SystemUI/res/values-zh-rTW/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rTW/config.xml
+++ b/packages/SystemUI/res/values-zh-rTW/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/config.xml b/packages/SystemUI/res/values-zu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zu/config.xml
+++ b/packages/SystemUI/res/values-zu/config.xml
@@ -22,6 +22,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
     <string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ae910fe..f2e5d3b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -46,7 +46,7 @@
     <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
 
     <!-- Component name of launcher service for overview to connect to -->
-    <string name="config_overviewServiceComponent" translateable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
+    <string name="config_overviewServiceComponent" translatable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
 
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3db79d7..e55c65a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -262,7 +262,11 @@
     <!-- The width of the panel that holds the quick settings. -->
     <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
 
-    <dimen name="volume_dialog_panel_width">120dp</dimen>
+    <!-- the amount the volume panel should be offset at the end from the view next to it (or
+    the scren edge, in portrait-->
+    <dimen name="volume_dialog_base_margin">12dp</dimen>
+
+    <dimen name="volume_dialog_panel_width">100dp</dimen>
 
     <dimen name="output_chooser_panel_width">320dp</dimen>
 
@@ -332,6 +336,8 @@
     <dimen name="qs_footer_padding_start">16dp</dimen>
     <dimen name="qs_footer_padding_end">24dp</dimen>
     <dimen name="qs_footer_icon_size">16dp</dimen>
+    <!-- Difference between drag handle margin in QQS and expanded QS -->
+    <dimen name="qs_footer_drag_handle_offset">6dp</dimen>
 
     <dimen name="qs_notif_collapsed_space">64dp</dimen>
 
@@ -902,4 +908,11 @@
     <dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen>
     <!-- Wireless Charging battery level text animation duration -->
     <integer name="config_batteryLevelTextAnimationDuration">400</integer>
+
+    <!-- Wired charging on AOD, text animation duration -->
+    <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
+    <!-- Wired charging on AOD, text animation duration -->
+    <integer name="wired_charging_aod_text_animation_duration_up">300</integer>
+    <!-- Wired charging on AOD, text animation distance -->
+    <integer name="wired_charging_aod_text_animation_distance">-30</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5557f8e..fadcbcd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1281,12 +1281,23 @@
     <string name="screen_pinning_title">Screen is pinned</string>
     <!-- Screen pinning dialog description. -->
     <string name="screen_pinning_description">This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin.</string>
+    <string name="screen_pinning_description_recents_invisible">This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin.</string>
     <!-- Screen pinning dialog description. -->
     <string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch &amp; hold Overview to unpin.</string>
+    <string name="screen_pinning_description_recents_invisible_accessible">This keeps it in view until you unpin. Touch &amp; hold Home to unpin.</string>
+    <!-- Notify use that they are in Lock-to-app -->
+    <string name="screen_pinning_toast">To unpin this screen, touch &amp; hold Back and Overview
+        buttons</string>
+    <string name="screen_pinning_toast_recents_invisible">To unpin this screen, touch &amp; hold Back
+        and Home buttons</string>
     <!-- Screen pinning positive response. -->
     <string name="screen_pinning_positive">Got it</string>
     <!-- Screen pinning negative response. -->
     <string name="screen_pinning_negative">No thanks</string>
+    <!-- Enter/Exiting screen pinning indication. -->
+    <string name="screen_pinning_start">Screen pinned</string>
+    <string name="screen_pinning_exit">Screen unpinned</string>
+
 
     <!-- Hide quick settings tile confirmation title -->
     <string name="quick_settings_reset_confirmation_title">Hide <xliff:g id="tile_label" example="Hotspot">%1$s</xliff:g>?</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2497d20..d2ed4d1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -410,16 +410,11 @@
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
-    <style name="TextAppearance.Volume.ZenSummary">
-        <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
+    <style name="TextAppearance.Volume.Header.Secondary">
+        <item name="android:textSize">12sp</item>
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
     </style>
 
-    <style name="TextAppearance.Volume.ZenDetail">
-        <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif</item>
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-    </style>
 
     <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
         <item name="android:background">@drawable/btn_borderless_rect</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index f9e1069..90e3b1e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.shared.system;
 
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -31,6 +33,7 @@
 import android.app.AppGlobals;
 import android.app.IAssistDataReceiver;
 import android.app.WindowConfiguration.ActivityType;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -47,6 +50,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.view.IRecentsAnimationController;
@@ -436,4 +440,23 @@
             Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
         }
     }
+
+    /**
+     * @return whether there is currently a locked task (ie. in screen pinning).
+     */
+    public boolean isLockToAppActive() {
+        try {
+            return ActivityManager.getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * @return whether screen pinning is enabled.
+     */
+    public boolean isLockToAppEnabled() {
+        final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
+        return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index b8cfa3e..aeef496 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -18,6 +18,7 @@
 
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.BounceInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
@@ -43,6 +44,7 @@
     public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
     public static final Interpolator PANEL_CLOSE_ACCELERATED
             = new PathInterpolator(0.3f, 0, 0.5f, 1);
+    public static final Interpolator BOUNCE = new BounceInterpolator();
 
     /**
      * Interpolator to be used when animating a move based on a click. Pair with enough duration.
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 8d8b726..b7e1d67 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -199,7 +199,7 @@
         launcherServiceIntent.setComponent(mLauncherComponentName);
         boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
                 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
-                UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
+                UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
         if (!bound) {
             // Retry after exponential backoff timeout
             final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
diff --git a/packages/SystemUI/src/com/android/systemui/SysUIToast.java b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
index 89bc82f..43b918d 100644
--- a/packages/SystemUI/src/com/android/systemui/SysUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
@@ -15,13 +15,19 @@
  */
 package com.android.systemui;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.view.WindowManager;
 import android.widget.Toast;
+import static android.widget.Toast.Duration;
 
 public class SysUIToast {
 
-    public static Toast makeText(Context context, CharSequence text, int duration) {
+    public static Toast makeText(Context context, @StringRes int resId, @Duration int duration) {
+        return makeText(context, context.getString(resId), duration);
+    }
+
+    public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
         Toast toast = Toast.makeText(context, text, duration);
         toast.getWindowParams().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index e661fa7..ea2a432 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -142,8 +142,12 @@
         final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
 
-        // NOTE: Keep the logic in sync with BatteryService.
-        // TODO: Propagate this value from BatteryService to system UI, really.
+        // Note LOW_POWER_MODE_TRIGGER_LEVEL can take any value between 0 and 100, but
+        // for the UI purposes, let's cap it at 15% -- i.e. even if the trigger level is higher
+        // like 50%, let's not show the "low battery" notification until it hits
+        // config_lowBatteryWarningLevel, which is 15% by default.
+        // LOW_POWER_MODE_TRIGGER_LEVEL is still used in other places as-is. For example, if it's
+        // 50, then battery saver kicks in when the battery level hits 50%.
         int warnLevel =  Math.min(defWarnLevel, lowPowerModeTriggerLevel);
 
         if (warnLevel == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 9c87e1b..7f34acb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
@@ -47,7 +46,6 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.ExpandableIndicator;
 import com.android.systemui.statusbar.phone.MultiUserSwitch;
 import com.android.systemui.statusbar.phone.SettingsButton;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -61,6 +59,7 @@
 public class QSFooterImpl extends FrameLayout implements QSFooter,
         OnClickListener, OnUserInfoChangedListener, EmergencyListener,
         SignalCallback, CommandQueue.Callbacks {
+
     private ActivityStarter mActivityStarter;
     private UserInfoController mUserInfoController;
     private SettingsButton mSettingsButton;
@@ -79,16 +78,22 @@
     protected MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
 
-    protected TouchAnimator mSettingsAlpha;
+    protected TouchAnimator mFooterAnimator;
     private float mExpansionAmount;
 
     protected View mEdit;
-    private TouchAnimator mAnimator;
+    private TouchAnimator mSettingsCogAnimator;
 
     private View mActionsContainer;
+    private View mDragHandle;
+    private final int mDragHandleExpandOffset;
 
     public QSFooterImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        mDragHandleExpandOffset = getResources().
+                getDimensionPixelSize(R.dimen.qs_footer_drag_handle_offset);
+
     }
 
     @Override
@@ -109,6 +114,7 @@
         mMultiUserSwitch = findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
 
+        mDragHandle = findViewById(R.id.qs_drag_handle_view);
         mActionsContainer = findViewById(R.id.qs_footer_actions_container);
 
         // RenderThread is doing more harm than good when touching the header (to expand quick
@@ -130,7 +136,7 @@
         int remaining = (width - numTiles * size) / (numTiles - 1);
         int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
 
-        mAnimator = new Builder()
+        mSettingsCogAnimator = new Builder()
                 .addFloat(mSettingsContainer, "translationX",
                         isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
                 .addFloat(mSettingsButton, "rotation", -120, 0)
@@ -152,19 +158,20 @@
     }
 
     private void updateResources() {
-        updateSettingsAnimator();
+        updateFooterAnimator();
     }
 
-    private void updateSettingsAnimator() {
-        mSettingsAlpha = createSettingsAlphaAnimator();
+    private void updateFooterAnimator() {
+        mFooterAnimator = createFooterAnimator();
     }
 
     @Nullable
-    private TouchAnimator createSettingsAlphaAnimator() {
+    private TouchAnimator createFooterAnimator() {
         return new TouchAnimator.Builder()
                 .addFloat(mDivider, "alpha", 0, 1)
                 .addFloat(mCarrierText, "alpha", 0, 1)
                 .addFloat(mActionsContainer, "alpha", 0, 1)
+                .addFloat(mDragHandle, "translationY", 0, -mDragHandleExpandOffset)
                 .build();
     }
 
@@ -183,10 +190,10 @@
     @Override
     public void setExpansion(float headerExpansionFraction) {
         mExpansionAmount = headerExpansionFraction;
-        if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
+        if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
 
-        if (mSettingsAlpha != null) {
-            mSettingsAlpha.setPosition(headerExpansionFraction);
+        if (mFooterAnimator != null) {
+            mFooterAnimator.setPosition(headerExpansionFraction);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index aaf6ef5..6205e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,8 +19,6 @@
 import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
-import android.app.AlarmManager;
-import android.app.AlarmManager.AlarmClockInfo;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,11 +28,9 @@
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
-import android.service.notification.ScheduleCalendar;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.service.quicksettings.Tile;
@@ -56,7 +52,6 @@
 import com.android.systemui.SysUIToast;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -197,7 +192,8 @@
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.slash.isSlashed = !state.value;
         state.label = getTileLabel();
-        state.secondaryLabel = getSecondaryLabel(zen != Global.ZEN_MODE_OFF);
+        state.secondaryLabel = ZenModeConfig.getDescription(mContext,zen != Global.ZEN_MODE_OFF,
+                mController.getConfig());
         state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
@@ -226,102 +222,6 @@
         state.expandedAccessibilityClassName = Switch.class.getName();
     }
 
-    /**
-     * Returns the secondary label to use for the given instance of do not disturb.
-     * - If turned on manually and end time is known, returns end time.
-     * - If turned on by an automatic rule, returns the automatic rule name.
-     * - If on due to an app, returns the app name.
-     * - If there's a combination of rules/apps that trigger, then shows the one that will
-     *  last the longest if applicable.
-     * @return null if do not disturb is off.
-     */
-    private String getSecondaryLabel(boolean zenOn) {
-        if (!zenOn) {
-            return null;
-        }
-
-        ZenModeConfig config = mController.getConfig();
-        String secondaryText = "";
-        long latestEndTime = -1;
-
-        // DND turned on by manual rule
-        if (config.manualRule != null) {
-            final Uri id = config.manualRule.conditionId;
-            if (config.manualRule.enabler != null) {
-                // app triggered manual rule
-                String appName = ZenModeConfig.getOwnerCaption(mContext, config.manualRule.enabler);
-                if (!appName.isEmpty()) {
-                    secondaryText = appName;
-                }
-            } else {
-                if (id == null) {
-                    // Do not disturb manually triggered to remain on forever until turned off
-                    // No subtext
-                    return null;
-                } else {
-                    latestEndTime = ZenModeConfig.tryParseCountdownConditionId(id);
-                    if (latestEndTime > 0) {
-                        final CharSequence formattedTime = ZenModeConfig.getFormattedTime(mContext,
-                                latestEndTime, ZenModeConfig.isToday(latestEndTime),
-                                mContext.getUserId());
-                        secondaryText = mContext.getString(R.string.qs_dnd_until, formattedTime);
-                    }
-                }
-            }
-        }
-
-        // DND turned on by an automatic rule
-        for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
-            if (automaticRule.isAutomaticActive()) {
-                if (ZenModeConfig.isValidEventConditionId(automaticRule.conditionId) ||
-                        ZenModeConfig.isValidScheduleConditionId(automaticRule.conditionId)) {
-                    // set text if automatic rule end time is the latest active rule end time
-                    long endTime = parseAutomaticRuleEndTime(automaticRule.conditionId);
-                    if (endTime > latestEndTime) {
-                        latestEndTime = endTime;
-                        secondaryText = automaticRule.name;
-                    }
-                } else {
-                    // set text if 3rd party rule
-                    return automaticRule.name;
-                }
-            }
-        }
-
-        return !secondaryText.equals("") ? secondaryText : null;
-    }
-
-    private long parseAutomaticRuleEndTime(Uri id) {
-        if (ZenModeConfig.isValidEventConditionId(id)) {
-            // cannot look up end times for events
-            return Long.MAX_VALUE;
-        }
-
-        if (ZenModeConfig.isValidScheduleConditionId(id)) {
-            ScheduleCalendar schedule = ZenModeConfig.toScheduleCalendar(id);
-            long endTimeMs = schedule.getNextChangeTime(System.currentTimeMillis());
-
-            // check if automatic rule will end on next alarm
-            if (schedule.exitAtAlarm()) {
-                long nextAlarm = getNextAlarm(mContext);
-                schedule.maybeSetNextAlarm(System.currentTimeMillis(), nextAlarm);
-                if (schedule.shouldExitForAlarm(endTimeMs)) {
-                    return nextAlarm;
-                }
-            }
-
-            return endTimeMs;
-        }
-
-        return -1;
-    }
-
-    private long getNextAlarm(Context context) {
-        final AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        final AlarmClockInfo info = alarms.getNextAlarmClock(mContext.getUserId());
-        return info != null ? info.getTriggerTime() : 0;
-    }
-
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.QS_DND;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 8bdbf28..d7f2a26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -102,7 +102,7 @@
         state.value = locationEnabled;
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
         if (state.disabledByPolicy == false) {
-            checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_LOCATION_MODE);
+            checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_LOCATION);
         }
         state.icon = mIcon;
         state.slash.isSlashed = !state.value;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 1da4deb..409c753 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -415,7 +415,7 @@
         final int activityType = runningTask != null
                 ? runningTask.configuration.windowConfiguration.getActivityType()
                 : ACTIVITY_TYPE_UNDEFINED;
-        boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive();
+        boolean screenPinningActive = ActivityManagerWrapper.getInstance().isLockToAppActive();
         boolean isRunningTaskInHomeOrRecentsStack =
                 activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
         if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index ee1b091..3f6f30b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -386,8 +386,7 @@
 
     public void toggleRecents(int growTarget) {
         // Skip preloading if the task is locked
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isScreenPinningActive()) {
+        if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
             return;
         }
 
@@ -409,8 +408,8 @@
             MutableBoolean isHomeStackVisible = new MutableBoolean(true);
             long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
 
+            SystemServicesProxy ssp = Recents.getSystemServices();
             if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
-                RecentsDebugFlags debugFlags = Recents.getDebugFlags();
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
                 if (!launchState.launchedWithAltTab) {
@@ -466,8 +465,7 @@
 
     public void preloadRecents() {
         // Skip preloading if the task is locked
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isScreenPinningActive()) {
+        if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
             return;
         }
 
@@ -481,6 +479,7 @@
         // RecentsActivity) only if there is a task to animate to.  Post this to ensure that we
         // don't block the touch feedback on the nav bar button which triggers this.
         mHandler.post(() -> {
+            SystemServicesProxy ssp = Recents.getSystemServices();
             if (!ssp.isRecentsActivityVisible(null)) {
                 ActivityManager.RunningTaskInfo runningTask =
                         ActivityManagerWrapper.getInstance().getRunningTask();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 316ad16..57f7818 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -23,15 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
-import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -43,6 +40,9 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.ArrayList;
@@ -233,11 +233,30 @@
                         .setVisibility(View.INVISIBLE);
             }
 
+            StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+            NavigationBarView navigationBarView = statusBar.getNavigationBarView();
+            final boolean recentsVisible = navigationBarView != null
+                    && navigationBarView.isRecentsButtonVisible();
             boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled();
+            int descriptionStringResId;
+            if (recentsVisible) {
+                mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(VISIBLE);
+                mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(INVISIBLE);
+                mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(INVISIBLE);
+                descriptionStringResId = touchExplorationEnabled
+                        ? R.string.screen_pinning_description_accessible
+                        : R.string.screen_pinning_description;
+            } else {
+                mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(INVISIBLE);
+                mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(VISIBLE);
+                mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(VISIBLE);
+                descriptionStringResId = touchExplorationEnabled
+                        ? R.string.screen_pinning_description_recents_invisible_accessible
+                        : R.string.screen_pinning_description_recents_invisible;
+            }
+
             ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
-                    .setText(touchExplorationEnabled
-                            ? R.string.screen_pinning_description_accessible
-                            : R.string.screen_pinning_description);
+                    .setText(descriptionStringResId);
             final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE;
             mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
             mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 613d9fb..93fd34a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -379,29 +379,6 @@
     }
 
     /**
-     * Returns a global setting.
-     */
-    public int getGlobalSetting(Context context, String setting) {
-        ContentResolver cr = context.getContentResolver();
-        return Settings.Global.getInt(cr, setting, 0);
-    }
-
-    /**
-     * Returns a system setting.
-     */
-    public int getSystemSetting(Context context, String setting) {
-        ContentResolver cr = context.getContentResolver();
-        return Settings.System.getInt(cr, setting, 0);
-    }
-
-    /**
-     * Returns a system property.
-     */
-    public String getSystemProperty(String key) {
-        return SystemProperties.get(key);
-    }
-
-    /**
      * Returns the smallest width/height.
      */
     public int getDeviceSmallestWidth() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 5be2900..3cc3273 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -95,6 +95,7 @@
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
 
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -2187,8 +2188,7 @@
     private void readSystemFlags() {
         SystemServicesProxy ssp = Recents.getSystemServices();
         mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
-        mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
-                Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isLockToAppEnabled();
     }
 
     private void updateStackActionButtonVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 79e9f7b..11bdf6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -24,6 +24,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.support.annotation.VisibleForTesting;
 import android.util.Pair;
 
@@ -90,6 +91,8 @@
     private static final int MSG_FINGERPRINT_ERROR             = 42 << MSG_SHIFT;
     private static final int MSG_FINGERPRINT_HIDE              = 43 << MSG_SHIFT;
     private static final int MSG_SHOW_CHARGING_ANIMATION       = 44 << MSG_SHIFT;
+    private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
+    private static final int MSG_SHOW_PINNING_TOAST_ESCAPE     = 46 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -148,6 +151,8 @@
         default void clickTile(ComponentName tile) { }
 
         default void handleSystemKey(int arg1) { }
+        default void showPinningEnterExitToast(boolean entering) { }
+        default void showPinningEscapeToast() { }
         default void handleShowGlobalActionsMenu() { }
         default void handleShowShutdownUi(boolean isReboot, String reason) { }
 
@@ -453,6 +458,21 @@
     }
 
     @Override
+    public void showPinningEnterExitToast(boolean entering) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ENTER_EXIT, entering).sendToTarget();
+        }
+    }
+
+    @Override
+    public void showPinningEscapeToast() {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ESCAPE).sendToTarget();
+        }
+    }
+
+
+    @Override
     public void showGlobalActionsMenu() {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
@@ -767,6 +787,16 @@
                         mCallbacks.get(i).showChargingAnimation(msg.arg1);
                     }
                     break;
+                case MSG_SHOW_PINNING_TOAST_ENTER_EXIT:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showPinningEnterExitToast((Boolean) msg.obj);
+                    }
+                    break;
+                case MSG_SHOW_PINNING_TOAST_ESCAPE:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showPinningEscapeToast();
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0a12be4..b7a1500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -44,6 +46,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.statusbar.phone.LockIcon;
@@ -192,7 +195,7 @@
             if  (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
                 hideTransientIndication();
             }
-            updateIndication();
+            updateIndication(false);
         } else if (!visible) {
             // If we unlock and return to keyguard quickly, previous error should not be shown
             hideTransientIndication();
@@ -204,7 +207,7 @@
      */
     public void setRestingIndication(String restingIndication) {
         mRestingIndication = restingIndication;
-        updateIndication();
+        updateIndication(false);
     }
 
     /**
@@ -265,7 +268,8 @@
             mWakeLock.setAcquired(true);
             hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
         }
-        updateIndication();
+
+        updateIndication(false);
     }
 
     /**
@@ -275,11 +279,11 @@
         if (mTransientIndication != null) {
             mTransientIndication = null;
             mHandler.removeMessages(MSG_HIDE_TRANSIENT);
-            updateIndication();
+            updateIndication(false);
         }
     }
 
-    protected final void updateIndication() {
+    protected final void updateIndication(boolean animate) {
         if (TextUtils.isEmpty(mTransientIndication)) {
             mWakeLock.setAcquired(false);
         }
@@ -295,7 +299,35 @@
                     mTextView.switchIndication(mTransientIndication);
                 } else if (mPowerPluggedIn) {
                     String indication = computePowerIndication();
-                    mTextView.switchIndication(indication);
+                    if (animate) {
+                        int yTranslation = mContext.getResources().getInteger(
+                                R.integer.wired_charging_aod_text_animation_distance);
+                        int animateUpDuration = mContext.getResources().getInteger(
+                                R.integer.wired_charging_aod_text_animation_duration_up);
+                        int animateDownDuration = mContext.getResources().getInteger(
+                                R.integer.wired_charging_aod_text_animation_duration_down);
+                        mTextView.animate()
+                                .translationYBy(yTranslation)
+                                .setInterpolator(Interpolators.LINEAR)
+                                .setDuration(animateUpDuration)
+                                .setListener(new AnimatorListenerAdapter() {
+                                    @Override
+                                    public void onAnimationStart(Animator animation) {
+                                        mTextView.switchIndication(indication);
+                                    }
+                                    @Override
+                                    public void onAnimationEnd(Animator animation) {
+                                        mTextView.animate()
+                                                .setDuration(animateDownDuration)
+                                                .setInterpolator(Interpolators.BOUNCE)
+                                                .translationYBy(-1 * yTranslation)
+                                                .setListener(null);
+                                    }
+                                });
+                    } else {
+                        mTextView.switchIndication(indication);
+                    }
+
                 } else {
                     String percentage = NumberFormat.getPercentInstance()
                             .format(mBatteryLevel / 100f);
@@ -390,7 +422,7 @@
         public void onReceive(Context context, Intent intent) {
             mHandler.post(() -> {
                 if (mVisible) {
-                    updateIndication();
+                    updateIndication(false);
                 }
             });
         }
@@ -412,7 +444,7 @@
             return;
         }
         mDozing = dozing;
-        updateIndication();
+        updateIndication(false);
         updateDisclosure();
     }
 
@@ -445,7 +477,7 @@
             mChargingWattage = status.maxChargingWattage;
             mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
             mBatteryLevel = status.level;
-            updateIndication();
+            updateIndication(!wasPluggedIn && mPowerPluggedIn);
             if (mDozing) {
                 if (!wasPluggedIn && mPowerPluggedIn) {
                     showTransientIndication(computePowerIndication());
@@ -551,7 +583,7 @@
         @Override
         public void onUserUnlocked() {
             if (mVisible) {
-                updateIndication();
+                updateIndication(false);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 65c45a3..1239a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -22,11 +22,13 @@
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
+import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.annotation.IdRes;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -69,6 +71,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
+import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -153,6 +156,18 @@
     private Animator mRotateShowAnimator;
     private Animator mRotateHideAnimator;
 
+    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
+        @Override
+        public void onConnectionChanged(boolean isConnected) {
+            mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
+            updateScreenPinningGestures();
+        }
+
+        @Override
+        public void onRecentsAnimationStarted() {
+            mNavigationBarView.setRecentsAnimationStarted(true);
+        }
+    };
 
     // ----- Fragment Lifecycle Callbacks -----
 
@@ -239,12 +254,14 @@
         filter.addAction(Intent.ACTION_SCREEN_ON);
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
         notifyNavigationBarScreenOn();
+        mOverviewProxyService.addCallback(mOverviewProxyListener);
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
         mNavigationBarView.getLightTransitionsController().destroy(getContext());
+        mOverviewProxyService.removeCallback(mOverviewProxyListener);
         getContext().unregisterReceiver(mBroadcastReceiver);
     }
 
@@ -514,6 +531,7 @@
         if (masked != mDisabledFlags1) {
             mDisabledFlags1 = masked;
             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
+            updateScreenPinningGestures();
         }
     }
 
@@ -528,7 +546,7 @@
     private boolean shouldDisableNavbarGestures() {
         return !mStatusBar.isDeviceProvisioned()
                 || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0
-                || mOverviewProxyService.getProxy() != null;
+                || mNavigationBarView.getRecentsButton().getVisibility() != View.VISIBLE;
     }
 
     private void repositionNavigationBar() {
@@ -540,6 +558,24 @@
                 ((View) mNavigationBarView.getParent()).getLayoutParams());
     }
 
+    private void updateScreenPinningGestures() {
+        if (mNavigationBarView == null) {
+            return;
+        }
+
+        // Change the cancel pin gesture to home and back if recents button is invisible
+        boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
+        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
+        if (recentsVisible) {
+            homeButton.setOnLongClickListener(this::onHomeLongClick);
+            backButton.setOnLongClickListener(this::onLongPressBackRecents);
+        } else {
+            homeButton.setOnLongClickListener(this::onLongPressBackHome);
+            backButton.setOnLongClickListener(this::onLongPressBackHome);
+        }
+    }
+
     private void notifyNavigationBarScreenOn() {
         mNavigationBarView.notifyScreenOn();
     }
@@ -555,11 +591,9 @@
 
         ButtonDispatcher backButton = mNavigationBarView.getBackButton();
         backButton.setLongClickable(true);
-        backButton.setOnLongClickListener(this::onLongPressBackRecents);
 
         ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
         homeButton.setOnTouchListener(this::onHomeTouch);
-        homeButton.setOnLongClickListener(this::onHomeLongClick);
 
         ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
@@ -569,6 +603,7 @@
         ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
         rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
         rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
+        updateScreenPinningGestures();
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -649,20 +684,29 @@
         mCommandQueue.toggleRecentApps();
     }
 
+    private boolean onLongPressBackHome(View v) {
+        return onLongPressNavigationButtons(v, R.id.back, R.id.home);
+    }
+
+    private boolean onLongPressBackRecents(View v) {
+        return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
+    }
+
     /**
-     * This handles long-press of both back and recents.  They are
-     * handled together to capture them both being long-pressed
+     * This handles long-press of both back and recents/home. Back is the common button with
+     * combination of recents if it is visible or home if recents is invisible.
+     * They are handled together to capture them both being long-pressed
      * at the same time to exit screen pinning (lock task).
      *
-     * When accessibility mode is on, only a long-press from recents
+     * When accessibility mode is on, only a long-press from recents/home
      * is required to exit.
      *
      * In all other circumstances we try to pass through long-press events
      * for Back, so that apps can still use it.  Which can be from two things.
      * 1) Not currently in screen pinning (lock task).
-     * 2) Back is long-pressed without recents.
+     * 2) Back is long-pressed without recents/home.
      */
-    private boolean onLongPressBackRecents(View v) {
+    private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) {
         try {
             boolean sendBackLongPress = false;
             IActivityManager activityManager = ActivityManagerNative.getDefault();
@@ -670,6 +714,7 @@
             boolean inLockTaskMode = activityManager.isInLockTaskMode();
             if (inLockTaskMode && !touchExplorationEnabled) {
                 long time = System.currentTimeMillis();
+
                 // If we recently long-pressed the other button then they were
                 // long-pressed 'together'
                 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
@@ -677,26 +722,32 @@
                     // When exiting refresh disabled flags.
                     mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
                     return true;
-                } else if ((v.getId() == R.id.back)
-                        && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) {
-                    // If we aren't pressing recents right now then they presses
-                    // won't be together, so send the standard long-press action.
-                    sendBackLongPress = true;
+                } else if (v.getId() == btnId1) {
+                    ButtonDispatcher button = btnId2 == R.id.recent_apps
+                            ? mNavigationBarView.getRecentsButton()
+                            : mNavigationBarView.getHomeButton();
+                    if (!button.getCurrentView().isPressed()) {
+                        // If we aren't pressing recents/home right now then they presses
+                        // won't be together, so send the standard long-press action.
+                        sendBackLongPress = true;
+                    }
                 }
                 mLastLockToAppLongPress = time;
             } else {
                 // If this is back still need to handle sending the long-press event.
-                if (v.getId() == R.id.back) {
+                if (v.getId() == btnId1) {
                     sendBackLongPress = true;
                 } else if (touchExplorationEnabled && inLockTaskMode) {
-                    // When in accessibility mode a long press that is recents (not back)
+                    // When in accessibility mode a long press that is recents/home (not back)
                     // should stop lock task.
                     activityManager.stopSystemLockTaskMode();
                     // When exiting refresh disabled flags.
                     mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
                     return true;
-                } else if (v.getId() == R.id.recent_apps) {
-                    return onLongPressRecents();
+                } else if (v.getId() == btnId2) {
+                    return btnId2 == R.id.recent_apps
+                            ? onLongPressRecents()
+                            : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView());
                 }
             }
             if (sendBackLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e04ba83..c37dd55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -207,23 +207,6 @@
         }
     }
 
-    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
-        @Override
-        public void onConnectionChanged(boolean isConnected) {
-            updateSlippery();
-            setDisabledFlags(mDisabledFlags, true);
-            setUpSwipeUpOnboarding(isConnected);
-        }
-
-        @Override
-        public void onRecentsAnimationStarted() {
-            mRecentsAnimationStarted = true;
-            if (mSwipeUpOnboarding != null) {
-                mSwipeUpOnboarding.onRecentsAnimationStarted();
-            }
-        }
-    };
-
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -280,6 +263,19 @@
         notifyVerticalChangedListener(mVertical);
     }
 
+    public void setRecentsAnimationStarted(boolean started) {
+        mRecentsAnimationStarted = started;
+        if (mSwipeUpOnboarding != null) {
+            mSwipeUpOnboarding.onRecentsAnimationStarted();
+        }
+    }
+
+    public void onConnectionChanged(boolean isConnected) {
+        updateSlippery();
+        setDisabledFlags(mDisabledFlags, true);
+        setUpSwipeUpOnboarding(isConnected);
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mGestureHelper.onTouchEvent(event)) {
@@ -353,6 +349,10 @@
         return mButtonDispatchers;
     }
 
+    public boolean isRecentsButtonVisible() {
+        return getRecentsButton().getVisibility() == View.VISIBLE;
+    }
+
     private void updateCarModeIcons(Context ctx) {
         mBackCarModeIcon = getDrawable(ctx,
                 R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -613,6 +613,9 @@
         final ViewGroup navbarView = ((ViewGroup) getParent());
         final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
                 .getLayoutParams();
+        if (lp == null) {
+            return;
+        }
         if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
             lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
             changed = true;
@@ -676,6 +679,12 @@
         }
     }
 
+    public void onOverviewProxyConnectionChanged(boolean isConnected) {
+        setSlippery(!isConnected);
+        setDisabledFlags(mDisabledFlags, true);
+        setUpSwipeUpOnboarding(isConnected);
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         mGestureHelper.onDraw(canvas);
@@ -873,7 +882,6 @@
         onPluginDisconnected(null); // Create default gesture helper
         Dependency.get(PluginManager.class).addPluginListener(this,
                 NavGesture.class, false /* Only one */);
-        mOverviewProxyService.addCallback(mOverviewProxyListener);
         setUpSwipeUpOnboarding(mOverviewProxyService.getProxy() != null);
     }
 
@@ -884,7 +892,6 @@
         if (mGestureHelper != null) {
             mGestureHelper.destroy();
         }
-        mOverviewProxyService.removeCallback(mOverviewProxyListener);
         setUpSwipeUpOnboarding(false);
     }
 
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
similarity index 70%
rename from services/core/java/com/android/server/am/LockTaskNotify.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
index 1dcb0ad..0d07ad9 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.am;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.os.SystemClock;
@@ -22,36 +22,37 @@
 import android.view.WindowManager;
 import android.widget.Toast;
 
-import com.android.internal.R;
+import com.android.systemui.R;
+import com.android.systemui.SysUIToast;
 
 /**
  *  Helper to manage showing/hiding a image to notify them that they are entering or exiting screen
  *  pinning mode. All exposed methods should be called from a handler thread.
  */
-public class LockTaskNotify {
-    private static final String TAG = "LockTaskNotify";
+public class ScreenPinningNotify {
+    private static final String TAG = "ScreenPinningNotify";
     private static final long SHOW_TOAST_MINIMUM_INTERVAL = 1000;
 
     private final Context mContext;
     private Toast mLastToast;
     private long mLastShowToastTime;
 
-    public LockTaskNotify(Context context) {
+    public ScreenPinningNotify(Context context) {
         mContext = context;
     }
 
     /** Show "Screen pinned" toast. */
     void showPinningStartToast() {
-        makeAllUserToastAndShow(R.string.lock_to_app_start);
+        makeAllUserToastAndShow(R.string.screen_pinning_start);
     }
 
     /** Show "Screen unpinned" toast. */
     void showPinningExitToast() {
-        makeAllUserToastAndShow(R.string.lock_to_app_exit);
+        makeAllUserToastAndShow(R.string.screen_pinning_exit);
     }
 
     /** Show a toast that describes the gesture the user should use to escape pinned mode. */
-    void showEscapeToast() {
+    void showEscapeToast(boolean isRecentsButtonVisible) {
         long showToastTime = SystemClock.elapsedRealtime();
         if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
             Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
@@ -60,14 +61,14 @@
         if (mLastToast != null) {
             mLastToast.cancel();
         }
-        mLastToast = makeAllUserToastAndShow(R.string.lock_to_app_toast);
+        mLastToast = makeAllUserToastAndShow(isRecentsButtonVisible
+                ? R.string.screen_pinning_toast
+                : R.string.screen_pinning_toast_recents_invisible);
         mLastShowToastTime = showToastTime;
     }
 
     private Toast makeAllUserToastAndShow(int resId) {
-        Toast toast = Toast.makeText(mContext, resId, Toast.LENGTH_LONG);
-        toast.getWindowParams().privateFlags |=
-                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        Toast toast = SysUIToast.makeText(mContext, resId, Toast.LENGTH_LONG);
         toast.show();
         return toast;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 426268b..1bf719a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -404,6 +404,13 @@
     protected NotificationEntryManager mEntryManager;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
 
+    /**
+     * Helper that is responsible for showing the right toast when a disallowed activity operation
+     * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
+     * fully locked mode we only show that unlocking is blocked.
+     */
+    private ScreenPinningNotify mScreenPinningNotify;
+
     // for disabling the status bar
     private int mDisabled1 = 0;
     private int mDisabled2 = 0;
@@ -830,7 +837,7 @@
         } catch (RemoteException ex) {
             // no window manager? good luck with that
         }
-
+        mScreenPinningNotify = new ScreenPinningNotify(mContext);
         mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
         mStackScroller.setStatusBar(this);
         mStackScroller.setGroupManager(mGroupManager);
@@ -2141,6 +2148,21 @@
 
     }
 
+    @Override
+    public void showPinningEnterExitToast(boolean entering) {
+        if (entering) {
+            mScreenPinningNotify.showPinningStartToast();
+        } else {
+            mScreenPinningNotify.showPinningExitToast();
+        }
+    }
+
+    @Override
+    public void showPinningEscapeToast() {
+        mScreenPinningNotify.showEscapeToast(getNavigationBarView() == null
+                || getNavigationBarView().isRecentsButtonVisible());
+    }
+
     boolean panelsEnabled() {
         return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
                 && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0c6e0f6..a131a61 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -18,6 +18,7 @@
 
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+import static android.media.AudioManager.STREAM_ACCESSIBILITY;
 
 import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -47,6 +48,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.support.v7.media.MediaRouter;
+import android.text.InputFilter;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
@@ -219,7 +221,7 @@
                         R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
                 addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
                         R.drawable.ic_volume_system_mute, false, false);
-                addRow(AudioManager.STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
+                addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
                         R.drawable.ic_volume_accessibility, true, false);
             }
         } else {
@@ -334,6 +336,9 @@
         row.view.setTag(row);
         row.header = row.view.findViewById(R.id.volume_row_header);
         row.header.setId(20 * row.stream);
+        if (stream == STREAM_ACCESSIBILITY) {
+            row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
+        }
         row.slider =  row.view.findViewById(R.id.volume_row_slider);
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.anim = null;
@@ -643,7 +648,7 @@
         if (ss.level == row.requestedLevel) {
             row.requestedLevel = -1;
         }
-        final boolean isA11yStream = row.stream == AudioManager.STREAM_ACCESSIBILITY;
+        final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY;
         final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
         final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
         final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
@@ -949,7 +954,7 @@
         public void onAccessibilityModeChanged(Boolean showA11yStream) {
             mShowA11yStream = showA11yStream == null ? false : showA11yStream;
             VolumeRow activeRow = getActiveRow();
-            if (!mShowA11yStream && AudioManager.STREAM_ACCESSIBILITY == activeRow.stream) {
+            if (!mShowA11yStream && STREAM_ACCESSIBILITY == activeRow.stream) {
                 dismissH(Events.DISMISS_STREAM_GONE);
             } else {
                 updateRowsH(activeRow);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
index f50a287..3d44381 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -14,26 +14,22 @@
 
 package com.android.systemui.volume;
 
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Gravity;
+import android.view.DisplayCutout;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
 
 import com.android.systemui.R;
 import com.android.systemui.util.leak.RotationUtils;
@@ -46,6 +42,9 @@
     private AnimatorSet mAnimation;
     private boolean mHasOutsideTouch;
     private int mRotation = ROTATION_NONE;
+    @Nullable
+    private DisplayCutout mDisplayCutout;
+
     public VolumeUiLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -60,6 +59,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
+        mDisplayCutout = null;
     }
 
     @Override
@@ -86,200 +86,64 @@
         updateRotation();
     }
 
+    private void setDisplayCutout() {
+        if (mDisplayCutout == null && getRootWindowInsets() != null) {
+            DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
+            if (cutout != null) {
+                mDisplayCutout = cutout;
+            }
+        }
+    }
+
     private void updateRotation() {
+        setDisplayCutout();
         int rotation = RotationUtils.getRotation(getContext());
         if (rotation != mRotation) {
-            rotate(mRotation, rotation);
+            updateSafeInsets(rotation);
             mRotation = rotation;
         }
     }
 
-    private void rotate(View view, int from, int to, boolean swapDimens) {
-        if (from != ROTATION_NONE && to != ROTATION_NONE) {
-            // Rather than handling this confusing case, just do 2 rotations.
-            rotate(view, from, ROTATION_NONE, swapDimens);
-            rotate(view, ROTATION_NONE, to, swapDimens);
-            return;
-        }
-        if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
-            rotateRight(view);
-        } else {
-            rotateLeft(view);
-        }
-        if (to != ROTATION_NONE) {
-            if (swapDimens && view instanceof LinearLayout) {
-                LinearLayout linearLayout = (LinearLayout) view;
-                linearLayout.setOrientation(LinearLayout.HORIZONTAL);
-                swapDimens(view);
-            }
-        } else {
-            if (swapDimens && view instanceof LinearLayout) {
-                LinearLayout linearLayout = (LinearLayout) view;
-                linearLayout.setOrientation(LinearLayout.VERTICAL);
-                swapDimens(view);
-            }
-        }
-    }
+    private void updateSafeInsets(int rotation) {
+        // Depending on our rotation, we may have to work around letterboxing from the right
+        // side from the navigation bar or a cutout.
 
-    private void rotate(int from, int to) {
-        View footer = mChild.findViewById(R.id.footer);
-        rotate(footer, from, to, false);
-        rotate(this, from, to, true);
-        rotate(mChild, from, to, true);
-        ViewGroup rows = mChild.findViewById(R.id.volume_dialog_rows);
-        rotate(rows, from, to, true);
-        swapOrientation((LinearLayout) rows);
-        int rowCount = rows.getChildCount();
-        for (int i = 0; i < rowCount; i++) {
-            View row = rows.getChildAt(i);
-            if (to == ROTATION_SEASCAPE) {
-                rotateSeekBars(row, to, 180);
-            } else if (to == ROTATION_LANDSCAPE) {
-                rotateSeekBars(row, to, 0);
-            } else {
-                rotateSeekBars(row, to, 270);
-            }
-            rotate(row, from, to, true);
-        }
-    }
+        MarginLayoutParams lp = (MarginLayoutParams) mChild.getLayoutParams();
 
-    private void swapOrientation(LinearLayout layout) {
-        if(layout.getOrientation() == LinearLayout.HORIZONTAL) {
-            layout.setOrientation(LinearLayout.VERTICAL);
-        } else {
-            layout.setOrientation(LinearLayout.HORIZONTAL);
-        }
-    }
-
-    private void swapDimens(View v) {
-        if (v == null) {
-            return;
-        }
-        ViewGroup.LayoutParams params = v.getLayoutParams();
-        int h = params.width;
-        params.width = params.height;
-        params.height = h;
-        v.setLayoutParams(params);
-    }
-
-    private void rotateSeekBars(View row, int to, int rotation) {
-        SeekBar seekbar = row.findViewById(R.id.volume_row_slider);
-        if (seekbar != null) {
-            seekbar.setRotation((float) rotation);
-        }
-
-        View parent = row.findViewById(R.id.volume_row_slider_frame);
-        swapDimens(parent);
-        ViewGroup.LayoutParams params = seekbar.getLayoutParams();
-        ViewGroup.LayoutParams parentParams = parent.getLayoutParams();
-        if (to != ROTATION_NONE) {
-            params.height = parentParams.height;
-            params.width = parentParams.width;
-        } else {
-            params.height = parentParams.width;
-            params.width = parentParams.height;
-        }
-        seekbar.setLayoutParams(params);
-    }
-
-    private int rotateGravityRight(int gravity) {
-        int retGravity = 0;
-        int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
-        final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                retGravity |= Gravity.CENTER_VERTICAL;
+        int margin = (int) getResources().getDimension(R.dimen.volume_dialog_base_margin);
+        switch (rotation) {
+            /*
+             * Landscape: <-|. Have to deal with the nav bar
+             * Seascape:  |->. Have to deal with the cutout
+             */
+            case RotationUtils.ROTATION_LANDSCAPE:
+                margin += getNavBarHeight();
                 break;
-            case Gravity.RIGHT:
-                retGravity |= Gravity.BOTTOM;
+            case RotationUtils.ROTATION_SEASCAPE:
+                margin += getDisplayCutoutHeight();
                 break;
-            case Gravity.LEFT:
             default:
-                retGravity |= Gravity.TOP;
                 break;
         }
 
-        switch (verticalGravity) {
-            case Gravity.CENTER_VERTICAL:
-                retGravity |= Gravity.CENTER_HORIZONTAL;
-                break;
-            case Gravity.BOTTOM:
-                retGravity |= Gravity.LEFT;
-                break;
-            case Gravity.TOP:
-            default:
-                retGravity |= Gravity.RIGHT;
-                break;
-        }
-        return retGravity;
+        lp.rightMargin = margin;
+        mChild.setLayoutParams(lp);
     }
 
-    private int rotateGravityLeft(int gravity) {
-        if (gravity == -1) {
-            gravity = Gravity.TOP | Gravity.START;
-        }
-        int retGravity = 0;
-        int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
-        final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                retGravity |= Gravity.CENTER_VERTICAL;
-                break;
-            case Gravity.RIGHT:
-                retGravity |= Gravity.TOP;
-                break;
-            case Gravity.LEFT:
-            default:
-                retGravity |= Gravity.BOTTOM;
-                break;
-        }
-
-        switch (verticalGravity) {
-            case Gravity.CENTER_VERTICAL:
-                retGravity |= Gravity.CENTER_HORIZONTAL;
-                break;
-            case Gravity.BOTTOM:
-                retGravity |= Gravity.RIGHT;
-                break;
-            case Gravity.TOP:
-            default:
-                retGravity |= Gravity.LEFT;
-                break;
-        }
-        return retGravity;
+    private int getNavBarHeight() {
+        return (int) getResources().getDimension(R.dimen.navigation_bar_size);
     }
 
-    private void rotateLeft(View v) {
-        if (v.getParent() instanceof FrameLayout) {
-            LayoutParams p = (LayoutParams) v.getLayoutParams();
-            p.gravity = rotateGravityLeft(p.gravity);
+    //TODO: Find a better way
+    private int getDisplayCutoutHeight() {
+        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+            return 0;
         }
 
-        v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
-                v.getPaddingLeft());
-        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
-        params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
-                params.leftMargin);
-        v.setLayoutParams(params);
+        Rect r = mDisplayCutout.getBoundingRect();
+        return r.bottom - r.top;
     }
 
-    private void rotateRight(View v) {
-        if (v.getParent() instanceof FrameLayout) {
-            LayoutParams p = (LayoutParams) v.getLayoutParams();
-            p.gravity = rotateGravityRight(p.gravity);
-        }
-
-        v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
-                v.getPaddingRight());
-        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
-        params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
-                params.rightMargin);
-        v.setLayoutParams(params);
-    }
 
     private void animateChild(int oldHeight, int newHeight) {
         if (true) return;
@@ -309,12 +173,6 @@
         return super.getOutlineProvider();
     }
 
-    @Override
-    public void setPressed(boolean pressed)
-    {
-        // Ignore presses because it activates the seekbar thumb unnecessarily.
-    }
-
     public void setOutsideTouchListener(OnClickListener onClickListener) {
         mHasOutsideTouch = true;
         requestLayout();
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f6a54af..c77dcc0 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -63,7 +63,7 @@
   // Number scans that returned at least one result.
   optional int32 num_non_empty_scan_results = 13;
 
-  // Number of scans that were one time.
+  // Number of single scans requests.
   optional int32 num_oneshot_scans = 14;
 
   // Number of repeated background scans that were scheduled to the chip.
@@ -376,6 +376,9 @@
 
   // Wifi power statistics
   optional WifiPowerStats wifi_power_stats = 92;
+
+  // Number of connectivity single scan requests.
+  optional int32 num_connectivity_oneshot_scans = 93;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -1155,4 +1158,4 @@
 
   // Amount of time wifi is in tx (ms)
   optional int64 tx_time_ms = 5;
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 30dfee8..f49cd67 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1840,14 +1840,6 @@
             if (!blocked) {
                 pw.println("    none");
             }
-            pw.print("  mUseAllowWhileIdleShortTime: [");
-            for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
-                if (mUseAllowWhileIdleShortTime.valueAt(i)) {
-                    UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i));
-                    pw.print(" ");
-                }
-            }
-            pw.println("]");
 
             pw.println("  mLastAlarmDeliveredForPackage:");
             for (int i = 0; i < mLastAlarmDeliveredForPackage.size(); i++) {
@@ -1913,14 +1905,32 @@
             if (mLastAllowWhileIdleDispatch.size() > 0) {
                 pw.println("  Last allow while idle dispatch times:");
                 for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) {
-                    pw.print("  UID ");
-                    UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i));
+                    pw.print("    UID ");
+                    final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
+                    UserHandle.formatUid(pw, uid);
                     pw.print(": ");
-                    TimeUtils.formatDuration(mLastAllowWhileIdleDispatch.valueAt(i),
-                            nowELAPSED, pw);
+                    final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
+                    TimeUtils.formatDuration(lastTime, nowELAPSED, pw);
+
+                    final long minInterval = getWhileIdleMinIntervalLocked(uid);
+                    pw.print("  Next allowed:");
+                    TimeUtils.formatDuration(lastTime + minInterval, nowELAPSED, pw);
+                    pw.print(" (");
+                    TimeUtils.formatDuration(minInterval, 0, pw);
+                    pw.print(")");
+
                     pw.println();
                 }
             }
+
+            pw.print("  mUseAllowWhileIdleShortTime: [");
+            for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
+                if (mUseAllowWhileIdleShortTime.valueAt(i)) {
+                    UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i));
+                    pw.print(" ");
+                }
+            }
+            pw.println("]");
             pw.println();
 
             if (mLog.dump(pw, "  Recent problems", "    ")) {
@@ -2181,13 +2191,23 @@
             for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) {
                 final long token = proto.start(
                         AlarmManagerServiceProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES);
-                proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID,
-                        mLastAllowWhileIdleDispatch.keyAt(i));
-                proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS,
-                        mLastAllowWhileIdleDispatch.valueAt(i));
+                final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
+                final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
+
+                proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID, uid);
+                proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime);
+                proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS,
+                        lastTime + getWhileIdleMinIntervalLocked(uid));
                 proto.end(token);
             }
 
+            for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
+                if (mUseAllowWhileIdleShortTime.valueAt(i)) {
+                    proto.write(AlarmManagerServiceProto.USE_ALLOW_WHILE_IDLE_SHORT_TIME,
+                            mUseAllowWhileIdleShortTime.keyAt(i));
+                }
+            }
+
             mLog.writeToProto(proto, AlarmManagerServiceProto.RECENT_PROBLEMS);
 
             final FilterStats[] topFilters = new FilterStats[10];
@@ -2866,6 +2886,23 @@
     private native int setKernelTime(long nativeData, long millis);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
+    private long getWhileIdleMinIntervalLocked(int uid) {
+        final boolean dozing = mPendingIdleUntil != null;
+        final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
+        if (!dozing && !ebs) {
+            return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
+        }
+        if (dozing) {
+            return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
+        }
+        if (mUseAllowWhileIdleShortTime.get(uid)) {
+            // if the last allow-while-idle went off while uid was fg, or the uid
+            // recently came into fg, don't block the alarm for long.
+            return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
+        }
+        return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
+    }
+
     boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
             final long nowRTC) {
         boolean hasWakeup = false;
@@ -2891,20 +2928,7 @@
                     // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can
                     // schedule such alarms.
                     final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, 0);
-                    final boolean dozing = mPendingIdleUntil != null;
-                    final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
-                    final long minTime;
-                    if (!dozing && !ebs) {
-                        minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
-                    } else if (dozing) {
-                        minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
-                    } else if (mUseAllowWhileIdleShortTime.get(alarm.creatorUid)) {
-                        // if the last allow-while-idle went off while uid was fg, or the uid
-                        // recently came into fg, don't block the alarm for long.
-                        minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
-                    } else {
-                        minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
-                    }
+                    final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid);
                     if (nowELAPSED < minTime) {
                         // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
                         // alarm went off for this app.  Reschedule the alarm to be in the
@@ -3641,6 +3665,7 @@
                 } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
                     if (uid >= 0) {
                         mLastAllowWhileIdleDispatch.delete(uid);
+                        mUseAllowWhileIdleShortTime.delete(uid);
                     }
                 } else {
                     if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
@@ -3693,7 +3718,6 @@
 
         @Override public void onUidGone(int uid, boolean disabled) {
             synchronized (mLock) {
-                mUseAllowWhileIdleShortTime.delete(uid);
                 if (disabled) {
                     removeForStoppedLocked(uid);
                 }
@@ -3701,9 +3725,6 @@
         }
 
         @Override public void onUidActive(int uid) {
-            synchronized (mLock) {
-                mUseAllowWhileIdleShortTime.put(uid, true);
-            }
         }
 
         @Override public void onUidIdle(int uid, boolean disabled) {
@@ -3766,6 +3787,18 @@
                 sendPendingBackgroundAlarmsLocked(uid, packageName);
             }
         }
+
+        @Override
+        public void onUidForeground(int uid, boolean foreground) {
+            synchronized (mLock) {
+                if (foreground) {
+                    mUseAllowWhileIdleShortTime.put(uid, true);
+
+                    // Note we don't have to drain the pending while-idle alarms here, because
+                    // this event should coincide with unblockAlarmsForUid().
+                }
+            }
+        }
     };
 
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
@@ -4026,7 +4059,7 @@
             if (allowWhileIdle) {
                 // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
                 mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
-                if (mForceAppStandbyTracker.isInForeground(alarm.creatorUid)) {
+                if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);
                 } else {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 7604044..339101f 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -54,6 +54,7 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
+import com.android.server.DeviceIdleController.LocalService;
 import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
 import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
 
@@ -64,18 +65,15 @@
 /**
  * Class to keep track of the information related to "force app standby", which includes:
  * - OP_RUN_ANY_IN_BACKGROUND for each package
- * - UID foreground state
+ * - UID foreground/active state
  * - User+system power save whitelist
  * - Temporary power save whitelist
  * - Global "force all apps standby" mode enforced by battery saver.
  *
- * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
- * each callback. For example, even when an UID comes into the foreground, if it wasn't
- * originally restricted, then there's no need to send an event.
- * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
+ * TODO: Make it a LocalService.
  *
  * Test:
- * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
  */
 public class ForceAppStandbyTracker {
     private static final String TAG = "ForceAppStandbyTracker";
@@ -108,6 +106,11 @@
     @GuardedBy("mLock")
     final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
 
+    /** UIDs that are active. */
+    @GuardedBy("mLock")
+    final SparseBooleanArray mActiveUids = new SparseBooleanArray();
+
+    /** UIDs that are in the foreground. */
     @GuardedBy("mLock")
     final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
 
@@ -160,18 +163,20 @@
     boolean mForcedAppStandbyEnabled;
 
     interface Stats {
-        int UID_STATE_CHANGED = 0;
-        int RUN_ANY_CHANGED = 1;
-        int ALL_UNWHITELISTED = 2;
-        int ALL_WHITELIST_CHANGED = 3;
-        int TEMP_WHITELIST_CHANGED = 4;
-        int EXEMPT_CHANGED = 5;
-        int FORCE_ALL_CHANGED = 6;
-        int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 7;
+        int UID_FG_STATE_CHANGED = 0;
+        int UID_ACTIVE_STATE_CHANGED = 1;
+        int RUN_ANY_CHANGED = 2;
+        int ALL_UNWHITELISTED = 3;
+        int ALL_WHITELIST_CHANGED = 4;
+        int TEMP_WHITELIST_CHANGED = 5;
+        int EXEMPT_CHANGED = 6;
+        int FORCE_ALL_CHANGED = 7;
+        int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
     }
 
     private final StatLogger mStatLogger = new StatLogger(new String[] {
-            "UID_STATE_CHANGED",
+            "UID_FG_STATE_CHANGED",
+            "UID_ACTIVE_STATE_CHANGED",
             "RUN_ANY_CHANGED",
             "ALL_UNWHITELISTED",
             "ALL_WHITELIST_CHANGED",
@@ -260,9 +265,16 @@
          * This is called when the foreground state changed for a UID.
          */
         private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+            onUidForeground(uid, sender.isUidInForeground(uid));
+        }
+
+        /**
+         * This is called when the active/idle state changed for a UID.
+         */
+        private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) {
             updateJobsForUid(uid);
 
-            if (sender.isInForeground(uid)) {
+            if (sender.isUidActive(uid)) {
                 unblockAlarmsForUid(uid);
             }
         }
@@ -355,6 +367,14 @@
          */
         public void unblockAlarmsForUidPackage(int uid, String packageName) {
         }
+
+        /**
+         * Called when a UID comes into the foreground or the background.
+         *
+         * @see #isUidInForeground(int)
+         */
+        public void onUidForeground(int uid, boolean foreground) {
+        }
     }
 
     @VisibleForTesting
@@ -404,8 +424,10 @@
 
             try {
                 mIActivityManager.registerUidObserver(new UidObserver(),
-                        ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
-                                | ActivityManager.UID_OBSERVER_ACTIVE,
+                        ActivityManager.UID_OBSERVER_GONE
+                                | ActivityManager.UID_OBSERVER_IDLE
+                                | ActivityManager.UID_OBSERVER_ACTIVE
+                                | ActivityManager.UID_OBSERVER_PROCSTATE,
                         ActivityManager.PROCESS_STATE_UNKNOWN, null);
                 mAppOpsService.startWatchingMode(TARGET_OP, null,
                         new AppOpsWatcher());
@@ -563,65 +585,77 @@
         return true;
     }
 
-    /**
-     * Puts a UID to {@link #mForegroundUids}.
-     */
-    void uidToForeground(int uid) {
-        synchronized (mLock) {
-            if (UserHandle.isCore(uid)) {
-                return;
-            }
-            // TODO This can be optimized by calling indexOfKey and sharing the index for get and
-            // put.
-            if (mForegroundUids.get(uid)) {
-                return;
-            }
-            mForegroundUids.put(uid, true);
-            mHandler.notifyUidForegroundStateChanged(uid);
+    private static boolean addUidToArray(SparseBooleanArray array, int uid) {
+        if (UserHandle.isCore(uid)) {
+            return false;
         }
+        if (array.get(uid)) {
+            return false;
+        }
+        array.put(uid, true);
+        return true;
     }
 
-    /**
-     * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
-     */
-    void uidToBackground(int uid, boolean remove) {
-        synchronized (mLock) {
-            if (UserHandle.isCore(uid)) {
-                return;
-            }
-            // TODO This can be optimized by calling indexOfKey and sharing the index for get and
-            // put.
-            if (!mForegroundUids.get(uid)) {
-                return;
-            }
-            if (remove) {
-                mForegroundUids.delete(uid);
-            } else {
-                mForegroundUids.put(uid, false);
-            }
-            mHandler.notifyUidForegroundStateChanged(uid);
+    private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) {
+        if (UserHandle.isCore(uid)) {
+            return false;
         }
+        if (!array.get(uid)) {
+            return false;
+        }
+        if (remove) {
+            array.delete(uid);
+        } else {
+            array.put(uid, false);
+        }
+        return true;
     }
 
     private final class UidObserver extends IUidObserver.Stub {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+            synchronized (mLock) {
+                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                    if (removeUidFromArray(mForegroundUids, uid, false)) {
+                        mHandler.notifyUidForegroundStateChanged(uid);
+                    }
+                } else {
+                    if (addUidToArray(mForegroundUids, uid)) {
+                        mHandler.notifyUidForegroundStateChanged(uid);
+                    }
+                }
+            }
         }
 
         @Override
         public void onUidGone(int uid, boolean disabled) {
-            uidToBackground(uid, /*remove=*/ true);
+            removeUid(uid, true);
         }
 
         @Override
         public void onUidActive(int uid) {
-            uidToForeground(uid);
+            synchronized (mLock) {
+                if (addUidToArray(mActiveUids, uid)) {
+                    mHandler.notifyUidActiveStateChanged(uid);
+                }
+            }
         }
 
         @Override
         public void onUidIdle(int uid, boolean disabled) {
             // Just to avoid excessive memcpy, don't remove from the array in this case.
-            uidToBackground(uid, /*remove=*/ false);
+            removeUid(uid, false);
+        }
+
+        private void removeUid(int uid, boolean remove) {
+            synchronized (mLock) {
+                if (removeUidFromArray(mActiveUids, uid, remove)) {
+                    mHandler.notifyUidActiveStateChanged(uid);
+                }
+                if (removeUidFromArray(mForegroundUids, uid, remove)) {
+                    mHandler.notifyUidForegroundStateChanged(uid);
+                }
+            }
         }
 
         @Override
@@ -695,22 +729,27 @@
     }
 
     private class MyHandler extends Handler {
-        private static final int MSG_UID_STATE_CHANGED = 1;
-        private static final int MSG_RUN_ANY_CHANGED = 2;
-        private static final int MSG_ALL_UNWHITELISTED = 3;
-        private static final int MSG_ALL_WHITELIST_CHANGED = 4;
-        private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
-        private static final int MSG_FORCE_ALL_CHANGED = 6;
-        private static final int MSG_USER_REMOVED = 7;
-        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
-        private static final int MSG_EXEMPT_CHANGED = 9;
+        private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
+        private static final int MSG_UID_FG_STATE_CHANGED = 1;
+        private static final int MSG_RUN_ANY_CHANGED = 3;
+        private static final int MSG_ALL_UNWHITELISTED = 4;
+        private static final int MSG_ALL_WHITELIST_CHANGED = 5;
+        private static final int MSG_TEMP_WHITELIST_CHANGED = 6;
+        private static final int MSG_FORCE_ALL_CHANGED = 7;
+        private static final int MSG_USER_REMOVED = 8;
+        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
+        private static final int MSG_EXEMPT_CHANGED = 10;
 
         public MyHandler(Looper looper) {
             super(looper);
         }
 
+        public void notifyUidActiveStateChanged(int uid) {
+            obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
+        }
+
         public void notifyUidForegroundStateChanged(int uid) {
-            obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
+            obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget();
         }
 
         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
@@ -718,26 +757,32 @@
         }
 
         public void notifyAllUnwhitelisted() {
+            removeMessages(MSG_ALL_UNWHITELISTED);
             obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
         }
 
         public void notifyAllWhitelistChanged() {
+            removeMessages(MSG_ALL_WHITELIST_CHANGED);
             obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
         }
 
         public void notifyTempWhitelistChanged() {
+            removeMessages(MSG_TEMP_WHITELIST_CHANGED);
             obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
         }
 
         public void notifyForceAllAppsStandbyChanged() {
+            removeMessages(MSG_FORCE_ALL_CHANGED);
             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
         }
 
         public void notifyForcedAppStandbyFeatureFlagChanged() {
+            removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
             obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
         }
 
         public void notifyExemptChanged() {
+            removeMessages(MSG_EXEMPT_CHANGED);
             obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
         }
 
@@ -763,11 +808,18 @@
 
             long start = mStatLogger.getTime();
             switch (msg.what) {
-                case MSG_UID_STATE_CHANGED:
+                case MSG_UID_ACTIVE_STATE_CHANGED:
+                    for (Listener l : cloneListeners()) {
+                        l.onUidActiveStateChanged(sender, msg.arg1);
+                    }
+                    mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
+                    return;
+
+                case MSG_UID_FG_STATE_CHANGED:
                     for (Listener l : cloneListeners()) {
                         l.onUidForegroundStateChanged(sender, msg.arg1);
                     }
-                    mStatLogger.logDurationStat(Stats.UID_STATE_CHANGED, start);
+                    mStatLogger.logDurationStat(Stats.UID_FG_STATE_CHANGED, start);
                     return;
 
                 case MSG_RUN_ANY_CHANGED:
@@ -846,18 +898,23 @@
                     mRunAnyRestrictedPackages.removeAt(i);
                 }
             }
-            for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
-                final int uid = mForegroundUids.keyAt(i);
-                final int userId = UserHandle.getUserId(uid);
-
-                if (userId == removedUserId) {
-                    mForegroundUids.removeAt(i);
-                }
-            }
+            cleanUpArrayForUser(mActiveUids, removedUserId);
+            cleanUpArrayForUser(mForegroundUids, removedUserId);
             mExemptedPackages.remove(removedUserId);
         }
     }
 
+    private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
+        for (int i = array.size() - 1; i >= 0; i--) {
+            final int uid = array.keyAt(i);
+            final int userId = UserHandle.getUserId(uid);
+
+            if (userId == removedUserId) {
+                array.removeAt(i);
+            }
+        }
+    }
+
     /**
      * Called by device idle controller to update the power save whitelists.
      */
@@ -954,7 +1011,7 @@
      */
     private boolean isRestricted(int uid, @NonNull String packageName,
             boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
-        if (isInForeground(uid)) {
+        if (isUidActive(uid)) {
             return false;
         }
         synchronized (mLock) {
@@ -982,13 +1039,29 @@
     }
 
     /**
+     * @return whether a UID is in active or not.
+     *
+     * Note this information is based on the UID proc state callback, meaning it's updated
+     * asynchronously and may subtly be stale. If the fresh data is needed, use
+     * {@link ActivityManagerInternal#getUidProcessState} instead.
+     */
+    public boolean isUidActive(int uid) {
+        if (UserHandle.isCore(uid)) {
+            return true;
+        }
+        synchronized (mLock) {
+            return mActiveUids.get(uid);
+        }
+    }
+
+    /**
      * @return whether a UID is in the foreground or not.
      *
      * Note this information is based on the UID proc state callback, meaning it's updated
      * asynchronously and may subtly be stale. If the fresh data is needed, use
      * {@link ActivityManagerInternal#getUidProcessState} instead.
      */
-    public boolean isInForeground(int uid) {
+    public boolean isUidInForeground(int uid) {
         if (UserHandle.isCore(uid)) {
             return true;
         }
@@ -1062,17 +1135,12 @@
             pw.println(mIsPluggedIn);
 
             pw.print(indent);
-            pw.print("Foreground uids: [");
+            pw.print("Active uids: ");
+            dumpUids(pw, mActiveUids);
 
-            String sep = "";
-            for (int i = 0; i < mForegroundUids.size(); i++) {
-                if (mForegroundUids.valueAt(i)) {
-                    pw.print(sep);
-                    pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
-                    sep = " ";
-                }
-            }
-            pw.println("]");
+            pw.print(indent);
+            pw.print("Foreground uids: ");
+            dumpUids(pw, mForegroundUids);
 
             pw.print(indent);
             pw.print("Whitelist appids: ");
@@ -1114,6 +1182,20 @@
         }
     }
 
+    private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
+        pw.print("[");
+
+        String sep = "";
+        for (int i = 0; i < array.size(); i++) {
+            if (array.valueAt(i)) {
+                pw.print(sep);
+                pw.print(UserHandle.formatUid(array.keyAt(i)));
+                sep = " ";
+            }
+        }
+        pw.println("]");
+    }
+
     public void dumpProto(ProtoOutputStream proto, long fieldId) {
         synchronized (mLock) {
             final long token = proto.start(fieldId);
@@ -1125,6 +1207,13 @@
                     mForceAllAppStandbyForSmallBattery);
             proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
 
+            for (int i = 0; i < mActiveUids.size(); i++) {
+                if (mActiveUids.valueAt(i)) {
+                    proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS,
+                            mActiveUids.keyAt(i));
+                }
+            }
+
             for (int i = 0; i < mForegroundUids.size(); i++) {
                 if (mForegroundUids.valueAt(i)) {
                     proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fc91d0d..2f42585 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -59,6 +59,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -468,7 +469,7 @@
     int mCurFocusedWindowSoftInputMode;
 
     /**
-     * The client by which {@link #mCurFocusedWindow} was reported.  Used only for debugging.
+     * The client by which {@link #mCurFocusedWindow} was reported.
      */
     ClientState mCurFocusedWindowClient;
 
@@ -2989,8 +2990,8 @@
         final int uid = Binder.getCallingUid();
         if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
             return true;
-        } else if (mCurClient != null && client != null
-                && mCurClient.client.asBinder() == client.asBinder()) {
+        } else if (mCurFocusedWindowClient != null && client != null
+                && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
             return true;
         } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
                 mAppOpsManager,
@@ -3026,6 +3027,15 @@
         }
     }
 
+    public boolean isInputMethodPickerShownForTest() {
+        synchronized(mMethodMap) {
+            if (mSwitchingDialog == null) {
+                return false;
+            }
+            return mSwitchingDialog.isShowing();
+        }
+    }
+
     @Override
     public void setInputMethod(IBinder token, String id) {
         if (!calledFromValidUser()) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6747be3..6743484 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -35,6 +35,7 @@
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.DisconnectCause;
+import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneStateListener;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
@@ -93,7 +94,8 @@
         IPhoneStateListener callback;
         IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
 
-        int callerUserId;
+        int callerUid;
+        int callerPid;
 
         int events;
 
@@ -117,7 +119,7 @@
                     + " callback=" + callback
                     + " onSubscriptionsChangedListenererCallback="
                                             + onSubscriptionsChangedListenerCallback
-                    + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
+                    + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
                     + " events=" + Integer.toHexString(events)
                     + " canReadPhoneState=" + canReadPhoneState + "}";
         }
@@ -356,6 +358,8 @@
     public void addOnSubscriptionsChangedListener(String callingPackage,
             IOnSubscriptionsChangedListener callback) {
         int callerUserId = UserHandle.getCallingUserId();
+        mContext.getSystemService(AppOpsManager.class)
+                .checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
             log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
                 + " callerUserId="  + callerUserId + " callback=" + callback
@@ -399,7 +403,8 @@
 
             r.onSubscriptionsChangedListenerCallback = callback;
             r.callingPackage = callingPackage;
-            r.callerUserId = callerUserId;
+            r.callerUid = Binder.getCallingUid();
+            r.callerPid = Binder.getCallingPid();
             r.events = 0;
             r.canReadPhoneState = true; // permission has been enforced above
             if (DBG) {
@@ -470,6 +475,8 @@
     private void listen(String callingPackage, IPhoneStateListener callback, int events,
             boolean notifyNow, int subId) {
         int callerUserId = UserHandle.getCallingUserId();
+        mContext.getSystemService(AppOpsManager.class)
+                .checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
             log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
                 + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -514,7 +521,8 @@
 
                 r.callback = callback;
                 r.callingPackage = callingPackage;
-                r.callerUserId = callerUserId;
+                r.callerUid = Binder.getCallingUid();
+                r.callerPid = Binder.getCallingPid();
                 boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
                         | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
                 r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
@@ -572,8 +580,10 @@
                         try {
                             if (DBG_LOC) log("listen: mCellLocation = "
                                     + mCellLocation[phoneId]);
-                            r.callback.onCellLocationChanged(
-                                    new Bundle(mCellLocation[phoneId]));
+                            if (checkLocationAccess(r)) {
+                                r.callback.onCellLocationChanged(
+                                        new Bundle(mCellLocation[phoneId]));
+                            }
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -619,7 +629,9 @@
                         try {
                             if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
                                     + mCellInfo.get(phoneId));
-                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+                            if (checkLocationAccess(r)) {
+                                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+                            }
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -979,7 +991,8 @@
                 mCellInfo.set(phoneId, cellInfo);
                 for (Record r : mRecords) {
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            idMatch(r.subId, subId, phoneId) &&
+                            checkLocationAccess(r)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1262,7 +1275,8 @@
                 mCellLocation[phoneId] = cellLocation;
                 for (Record r : mRecords) {
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            idMatch(r.subId, subId, phoneId) &&
+                            checkLocationAccess(r)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1706,10 +1720,11 @@
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
-            valid = r.callerUserId ==  foregroundUser && r.matchPhoneStateListenerEvent(events);
+            valid = UserHandle.getUserId(r.callerUid) == foregroundUser
+                    && r.matchPhoneStateListenerEvent(events);
             if (DBG | DBG_LOC) {
                 log("validateEventsAndUserLocked: valid=" + valid
-                        + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser
+                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
                         + " r.events=" + r.events + " events=" + events);
             }
         } finally {
@@ -1741,6 +1756,16 @@
         }
     }
 
+    private boolean checkLocationAccess(Record r) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            return LocationAccessPolicy.canAccessCellLocation(mContext,
+                    r.callingPackage, r.callerUid, r.callerPid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private void checkPossibleMissNotify(Record r, int phoneId) {
         int events = r.events;
 
@@ -1788,7 +1813,9 @@
                     log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
                             + mCellInfo.get(phoneId));
                 }
-                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+                if (checkLocationAccess(r)) {
+                    r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+                }
             } catch (RemoteException ex) {
                 mRemoveList.add(r.binder);
             }
@@ -1836,7 +1863,9 @@
             try {
                 if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
                         + mCellLocation[phoneId]);
-                r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+                if (checkLocationAccess(r)) {
+                    r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+                }
             } catch (RemoteException ex) {
                 mRemoveList.add(r.binder);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f370393..8d1632a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -802,6 +802,7 @@
                 doDump(fd, pw, new String[]{"recents"}, asProto);
                 doDump(fd, pw, new String[]{"lastanr"}, asProto);
                 doDump(fd, pw, new String[]{"starter"}, asProto);
+                doDump(fd, pw, new String[]{"containers"}, asProto);
                 if (mAssociations.size() > 0) {
                     doDump(fd, pw, new String[]{"associations"}, asProto);
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f0c90e0..24a77c7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -115,6 +115,7 @@
     private int mActivityType;
     private int mTaskId;
     private boolean mIsTaskOverlay;
+    private boolean mIsLockTask;
 
     final boolean mDumping;
 
@@ -278,6 +279,7 @@
         mActivityType = ACTIVITY_TYPE_UNDEFINED;
         mTaskId = INVALID_TASK_ID;
         mIsTaskOverlay = false;
+        mIsLockTask = false;
 
         return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
             @Override
@@ -334,6 +336,8 @@
                     mTaskId = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("--task-overlay")) {
                     mIsTaskOverlay = true;
+                } else if (opt.equals("--lock-task")) {
+                    mIsLockTask = true;
                 } else {
                     return false;
                 }
@@ -429,13 +433,22 @@
                 options.setLaunchActivityType(mActivityType);
             }
             if (mTaskId != INVALID_TASK_ID) {
-                options = ActivityOptions.makeBasic();
+                if (options == null) {
+                    options = ActivityOptions.makeBasic();
+                }
                 options.setLaunchTaskId(mTaskId);
 
                 if (mIsTaskOverlay) {
                     options.setTaskOverlay(true, true /* canResume */);
                 }
             }
+            android.util.Log.d("bfranz", "I was here: " + mIsLockTask);
+            if (mIsLockTask) {
+                if (options == null) {
+                    options = ActivityOptions.makeBasic();
+                }
+                options.setLockTaskMode(true);
+            }
             if (mWaitOption) {
                 result = mInterface.startActivityAndWait(null, null, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo,
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 21f9135..e5762d2 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -38,6 +38,7 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -142,14 +143,6 @@
     TelecomManager mTelecomManager;
 
     /**
-     * Helper that is responsible for showing the right toast when a disallowed activity operation
-     * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
-     * fully locked mode we only show that unlocking is blocked.
-     */
-    @VisibleForTesting
-    LockTaskNotify mLockTaskNotify;
-
-    /**
      * The chain of tasks in LockTask mode, in the order of when they first entered LockTask mode.
      *
      * The first task in the list, which started the current LockTask session, is called the root
@@ -475,7 +468,7 @@
                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
             }
             if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
-                getLockTaskNotify().showPinningExitToast();
+                getStatusBarService().showPinningEnterExitToast(false /* entering */);
             }
         } catch (RemoteException ex) {
             throw new RuntimeException(ex);
@@ -490,7 +483,11 @@
      */
     void showLockTaskToast() {
         if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
-            mHandler.post(() -> getLockTaskNotify().showEscapeToast());
+            try {
+                getStatusBarService().showPinningEscapeToast();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to send pinning escape toast", e);
+            }
         }
     }
 
@@ -582,7 +579,7 @@
         // When lock task starts, we disable the status bars.
         try {
             if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
-                getLockTaskNotify().showPinningStartToast();
+                getStatusBarService().showPinningEnterExitToast(true /* entering */);
             }
             mLockTaskModeState = lockTaskModeState;
             setStatusBarState(lockTaskModeState, userId);
@@ -835,15 +832,6 @@
         return mTelecomManager;
     }
 
-    // Should only be called on the handler thread
-    @NonNull
-    private LockTaskNotify getLockTaskNotify() {
-        if (mLockTaskNotify == null) {
-            mLockTaskNotify = new LockTaskNotify(mContext);
-        }
-        return mLockTaskNotify;
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "LockTaskController");
         prefix = prefix + "  ";
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 3bb3d1f..5af19ec 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -21,6 +21,7 @@
 import android.hardware.broadcastradio.V2_0.AmFmBandRange;
 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
 import android.hardware.broadcastradio.V2_0.Announcement;
+import android.hardware.broadcastradio.V2_0.DabTableEntry;
 import android.hardware.broadcastradio.V2_0.IdentifierType;
 import android.hardware.broadcastradio.V2_0.ProgramFilter;
 import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
@@ -196,9 +197,15 @@
         return bands.toArray(new RadioManager.BandDescriptor[bands.size()]);
     }
 
+    private static @Nullable Map<String, Integer> dabConfigFromHal(
+            @Nullable List<DabTableEntry> config) {
+        if (config == null) return null;
+        return config.stream().collect(Collectors.toMap(e -> e.label, e -> e.frequency));
+    }
+
     static @NonNull RadioManager.ModuleProperties
     propertiesFromHal(int id, @NonNull String serviceName, @NonNull Properties prop,
-            @Nullable AmFmRegionConfig amfmConfig) {
+            @Nullable AmFmRegionConfig amfmConfig, @Nullable List<DabTableEntry> dabConfig) {
         Objects.requireNonNull(serviceName);
         Objects.requireNonNull(prop);
 
@@ -228,6 +235,7 @@
                 true,  // isBgScanSupported is deprecated
                 supportedProgramTypes,
                 supportedIdentifierTypes,
+                dabConfigFromHal(dabConfig),
                 vendorInfoFromHal(prop.vendorInfo)
         );
     }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 50f032d..daec97a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -24,6 +24,7 @@
 import android.hardware.radio.RadioManager;
 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
 import android.hardware.broadcastradio.V2_0.Announcement;
+import android.hardware.broadcastradio.V2_0.DabTableEntry;
 import android.hardware.broadcastradio.V2_0.IAnnouncementListener;
 import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
 import android.hardware.broadcastradio.V2_0.ICloseHandle;
@@ -58,12 +59,17 @@
             if (service == null) return null;
 
             Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
-            service.getAmFmRegionConfig(false, (int result, AmFmRegionConfig config) -> {
+            service.getAmFmRegionConfig(false, (result, config) -> {
                 if (result == Result.OK) amfmConfig.value = config;
             });
 
-            RadioManager.ModuleProperties prop =
-                    Convert.propertiesFromHal(idx, fqName, service.getProperties(), amfmConfig.value);
+            Mutable<List<DabTableEntry>> dabConfig = new Mutable<>();
+            service.getDabRegionConfig((result, config) -> {
+                if (result == Result.OK) dabConfig.value = config;
+            });
+
+            RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
+                    service.getProperties(), amfmConfig.value, dabConfig.value);
 
             return new RadioModule(service, prop);
         } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 2e4567a..5eb7700 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -92,7 +92,7 @@
             jobStatus.printUniqueId(pw);
             pw.print(" from ");
             UserHandle.formatUid(pw, uid);
-            pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
+            pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle");
             if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
                     mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
                 pw.print(", whitelisted");
@@ -136,7 +136,7 @@
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
 
             proto.write(TrackedJob.IS_IN_FOREGROUND,
-                    mForceAppStandbyTracker.isInForeground(sourceUid));
+                    mForceAppStandbyTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
                     mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) ||
                     mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid));
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 28fa86b..e715724 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -383,8 +383,8 @@
             return KeyStore.getInstance();
         }
 
-        public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
-            return RecoverableKeyStoreManager.getInstance(mContext);
+        public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
+            return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
         }
 
         public IStorageManager getStorageManager() {
@@ -413,7 +413,7 @@
         mInjector = injector;
         mContext = injector.getContext();
         mKeyStore = injector.getKeyStore();
-        mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
+        mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
         mHandler = injector.getHandler();
         mStrongAuth = injector.getStrongAuth();
         mActivityManager = injector.getActivityManager();
@@ -1887,7 +1887,7 @@
         mSpManager.removeUser(userId);
         mStorage.removeUser(userId);
         mStrongAuth.removeUser(userId);
-        cleanSpCache();
+        tryRemoveUserFromSpCacheLater(userId);
 
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserRemoved(userId);
@@ -2064,6 +2064,16 @@
         return mRecoverableKeyStoreManager.generateAndStoreKey(alias);
     }
 
+    @Override
+    public String generateKey(@NonNull String alias, byte[] account) throws RemoteException {
+        return mRecoverableKeyStoreManager.generateKey(alias, account);
+    }
+
+    @Override
+    public String getKey(@NonNull String alias) throws RemoteException {
+        return mRecoverableKeyStoreManager.getKey(alias);
+    }
+
     private static final String[] VALID_SETTINGS = new String[] {
             LockPatternUtils.LOCKOUT_PERMANENT_KEY,
             LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -2141,6 +2151,13 @@
     private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
 
     private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
+        // Preemptively cache the SP and then try to remove it in a handler.
+        Slog.i(TAG, "Caching SP for user " + userId);
+        synchronized (mSpManager) {
+            mSpCache.put(userId, auth);
+        }
+        tryRemoveUserFromSpCacheLater(userId);
+
         // Pass the primary user's auth secret to the HAL
         if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
             try {
@@ -2154,33 +2171,25 @@
                 Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
             }
         }
-
-        // Update the SP cache, removing the entry when allowed
-        synchronized (mSpManager) {
-            if (shouldCacheSpForUser(userId)) {
-                Slog.i(TAG, "Caching SP for user " + userId);
-                mSpCache.put(userId, auth);
-            } else {
-                Slog.i(TAG, "Not caching SP for user " + userId);
-                mSpCache.delete(userId);
-            }
-        }
     }
 
-    /** Clean up the SP cache by removing unneeded entries. */
-    private void cleanSpCache() {
-        synchronized (mSpManager) {
-            // Preserve indicies after removal by iterating backwards
-            for (int i = mSpCache.size() - 1; i >= 0; --i) {
-                final int userId = mSpCache.keyAt(i);
-                if (!shouldCacheSpForUser(userId)) {
-                    Slog.i(TAG, "Uncaching SP for user " + userId);
-                    mSpCache.removeAt(i);
+    private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
+        mHandler.post(() -> {
+            if (!shouldCacheSpForUser(userId)) {
+                // The transition from 'should not cache' to 'should cache' can only happen if
+                // certain admin apps are installed after provisioning e.g. via adb. This is not
+                // a common case and we do not seamlessly support; it may result in the SP not
+                // being cached when it is needed. The cache can be re-populated by verifying
+                // the credential again.
+                Slog.i(TAG, "Removing SP from cache for user " + userId);
+                synchronized (mSpManager) {
+                    mSpCache.remove(userId);
                 }
             }
-        }
+        });
     }
 
+    /** Do not hold any of the locks from this service when calling. */
     private boolean shouldCacheSpForUser(@UserIdInt int userId) {
         // Before the user setup has completed, an admin could be installed that requires the SP to
         // be cached (see below).
@@ -2731,7 +2740,7 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri) {
+        public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
             if (mDeviceProvisionedUri.equals(uri)) {
                 updateRegistration();
 
@@ -2741,7 +2750,7 @@
                     clearFrpCredentialIfOwnerNotSecure();
                 }
             } else if (mUserSetupCompleteUri.equals(uri)) {
-                cleanSpCache();
+                tryRemoveUserFromSpCacheLater(userId);
             }
         }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
index 59132da..285e722 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
@@ -16,10 +16,13 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
+import java.io.IOException;
+import java.security.cert.CertificateException;
 import java.security.Key;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchAlgorithmException;
 import java.security.UnrecoverableKeyException;
 
 /**
@@ -27,6 +30,7 @@
  */
 public class KeyStoreProxyImpl implements KeyStoreProxy {
 
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private final KeyStore mKeyStore;
 
     /**
@@ -57,4 +61,21 @@
     public void deleteEntry(String alias) throws KeyStoreException {
         mKeyStore.deleteEntry(alias);
     }
+
+    /**
+     * Returns AndroidKeyStore-provided {@link KeyStore}, having already invoked
+     * {@link KeyStore#load(KeyStore.LoadStoreParameter)}.
+     *
+     * @throws KeyStoreException if there was a problem getting or initializing the key store.
+     */
+    public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        try {
+            keyStore.load(/*param=*/ null);
+        } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
+            // Should never happen.
+            throw new KeyStoreException("Unable to load keystore.", e);
+        }
+        return keyStore;
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index ec72b22..fda6cdf 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -37,21 +37,23 @@
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryController;
 import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.KeyStore;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.HexDump;
+import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
 
 import java.security.InvalidKeyException;
-import java.security.KeyStoreException;
 import java.security.KeyFactory;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
 import java.security.spec.InvalidKeySpecException;
+import java.security.UnrecoverableKeyException;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -82,18 +84,23 @@
     private final RecoverableKeyGenerator mRecoverableKeyGenerator;
     private final RecoverySnapshotStorage mSnapshotStorage;
     private final PlatformKeyManager mPlatformKeyManager;
+    private final KeyStore mKeyStore;
+    private final ApplicationKeyStorage mApplicationKeyStorage;
 
     /**
      * Returns a new or existing instance.
      *
      * @hide
      */
-    public static synchronized RecoverableKeyStoreManager getInstance(Context context) {
+    public static synchronized RecoverableKeyStoreManager
+            getInstance(Context context, KeyStore keystore) {
         if (mInstance == null) {
             RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context);
             PlatformKeyManager platformKeyManager;
+            ApplicationKeyStorage applicationKeyStorage;
             try {
                 platformKeyManager = PlatformKeyManager.getInstance(context, db);
+                applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore);
             } catch (NoSuchAlgorithmException e) {
                 // Impossible: all algorithms must be supported by AOSP
                 throw new RuntimeException(e);
@@ -103,12 +110,14 @@
 
             mInstance = new RecoverableKeyStoreManager(
                     context.getApplicationContext(),
+                    keystore,
                     db,
                     new RecoverySessionStorage(),
                     Executors.newSingleThreadExecutor(),
                     new RecoverySnapshotStorage(),
                     new RecoverySnapshotListenersStorage(),
-                    platformKeyManager);
+                    platformKeyManager,
+                    applicationKeyStorage);
         }
         return mInstance;
     }
@@ -116,19 +125,23 @@
     @VisibleForTesting
     RecoverableKeyStoreManager(
             Context context,
+            KeyStore keystore,
             RecoverableKeyStoreDb recoverableKeyStoreDb,
             RecoverySessionStorage recoverySessionStorage,
             ExecutorService executorService,
             RecoverySnapshotStorage snapshotStorage,
             RecoverySnapshotListenersStorage listenersStorage,
-            PlatformKeyManager platformKeyManager) {
+            PlatformKeyManager platformKeyManager,
+            ApplicationKeyStorage applicationKeyStorage) {
         mContext = context;
+        mKeyStore = keystore;
         mDatabase = recoverableKeyStoreDb;
         mRecoverySessionStorage = recoverySessionStorage;
         mExecutorService = executorService;
         mListenersStorage = listenersStorage;
         mSnapshotStorage = snapshotStorage;
         mPlatformKeyManager = platformKeyManager;
+        mApplicationKeyStorage = applicationKeyStorage;
 
         try {
             mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase);
@@ -406,6 +419,7 @@
     }
 
     /**
+     * Deprecated
      * Generates a key named {@code alias} in the recoverable store for the calling uid. Then
      * returns the raw key material.
      *
@@ -450,9 +464,55 @@
         boolean wasRemoved = mDatabase.removeKey(uid, alias);
         if (wasRemoved) {
             mDatabase.setShouldCreateSnapshot(userId, uid, true);
+            mApplicationKeyStorage.deleteEntry(userId, uid, alias);
         }
     }
 
+    /**
+     * Generates a key named {@code alias} in caller's namespace.
+     * The key is stored in system service keystore namespace.
+     *
+     * @return grant alias, which caller can use to access the key.
+     */
+    public String generateKey(@NonNull String alias, byte[] account) throws RemoteException {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+
+        PlatformEncryptionKey encryptionKey;
+        try {
+            encryptionKey = mPlatformKeyManager.getEncryptKey(userId);
+        } catch (NoSuchAlgorithmException e) {
+            // Impossible: all algorithms must be supported by AOSP
+            throw new RuntimeException(e);
+        } catch (KeyStoreException | UnrecoverableKeyException e) {
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+        } catch (InsecureUserException e) {
+            throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
+        }
+
+        try {
+            byte[] secretKey =
+                    mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId, uid, alias);
+            mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, secretKey);
+            String grantAlias = mApplicationKeyStorage.getGrantAlias(userId, uid, alias);
+            return grantAlias;
+        } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+    /**
+     * Gets a key named {@code alias} in caller's namespace.
+     *
+     * @return grant alias, which caller can use to access the key.
+     */
+    public String getKey(@NonNull String alias) throws RemoteException {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        String grantAlias = mApplicationKeyStorage.getGrantAlias(userId, uid, alias);
+        return grantAlias;
+    }
+
     private byte[] decryptRecoveryKey(
             RecoverySessionStorage.Entry sessionEntry, byte[] encryptedClaimResponse)
             throws RemoteException, ServiceSpecificException {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
new file mode 100644
index 0000000..600a534
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.storage;
+
+import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
+
+import android.annotation.Nullable;
+import android.os.ServiceSpecificException;
+import android.security.Credentials;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.KeyStore;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.locksettings.recoverablekeystore.KeyStoreProxy;
+import com.android.server.locksettings.recoverablekeystore.KeyStoreProxyImpl;
+
+import java.security.KeyStore.SecretKeyEntry;
+import java.security.KeyStoreException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Storage for Application keys in LockSettings service KeyStore namespace.
+ *
+ * <p> Uses KeyStore's grant mechanism to make keys usable by application process without
+ * revealing key material
+ */
+public class ApplicationKeyStorage {
+    private static final String APPLICATION_KEY_ALIAS_PREFIX =
+            "com.android.server.locksettings.recoverablekeystore/application/";
+
+    KeyStoreProxy mKeyStore;
+    KeyStore mKeystoreService;
+
+    public static ApplicationKeyStorage getInstance(KeyStore keystoreService)
+            throws KeyStoreException {
+        return new ApplicationKeyStorage(
+                new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()),
+                keystoreService);
+    }
+
+    @VisibleForTesting
+    ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) {
+        mKeyStore = keyStore;
+        mKeystoreService = keystoreService;
+    }
+
+    /**
+     * Returns grant alias, valid in Applications namespace.
+     */
+    public @Nullable String getGrantAlias(int userId, int uid, String alias) {
+        // Aliases used by {@link KeyStore} are different than used by public API.
+        // {@code USER_PRIVATE_KEY} prefix is used secret keys.
+        String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias);
+        return mKeystoreService.grant(keystoreAlias, uid);
+    }
+
+    public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
+            throws KeyStoreException {
+        try {
+            mKeyStore.setEntry(
+                getInternalAlias(userId, uid, alias),
+                new SecretKeyEntry(
+                    new SecretKeySpec(secretKey, KeyProperties.KEY_ALGORITHM_AES)),
+                new KeyProtection.Builder(
+                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .build());
+        } catch (KeyStoreException e) {
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+    public void deleteEntry(int userId, int uid, String alias) {
+        try {
+            mKeyStore.deleteEntry(getInternalAlias(userId, uid, alias));
+        } catch (KeyStoreException e) {
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+    /**
+     * Returns the alias in locksettins service's KeyStore namespace used for given application key.
+     *
+     * <p>These IDs look as follows:
+     * {@code com.security.recoverablekeystore/application/<userId>/<uid>/<alias>}
+     *
+     * @param userId The ID of the user
+     * @param uid The uid
+     * @param alias - alias in application's namespace
+     * @return The alias.
+     */
+    private String getInternalAlias(int userId, int uid, String alias) {
+        return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias;
+    }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 502760a..fd435f9 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -771,7 +771,7 @@
      * Called whenever packages change, the user switches, or the secure setting
      * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
      */
-    private void rebindServices(boolean forceRebind) {
+    protected void rebindServices(boolean forceRebind) {
         if (DEBUG) Slog.d(TAG, "rebindServices");
         final int[] userIds = mUserProfiles.getCurrentProfileIds();
         final int nUserIds = userIds.length;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 727e7ee..b25124a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2891,6 +2891,7 @@
         // Backup/restore interface
         @Override
         public byte[] getBackupPayload(int user) {
+            checkCallerIsSystem();
             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
             //TODO: http://b/22388012
             if (user != UserHandle.USER_SYSTEM) {
@@ -2911,6 +2912,7 @@
 
         @Override
         public void applyRestore(byte[] payload, int user) {
+            checkCallerIsSystem();
             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
             if (payload == null) {
@@ -5687,6 +5689,12 @@
             mListeners.unregisterService(removed.service, removed.userid);
         }
 
+        @Override
+        public void onUserUnlocked(int user) {
+            if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
+            rebindServices(true);
+        }
+
         public void onNotificationEnqueued(final NotificationRecord r) {
             final StatusBarNotification sbn = r.sbn;
             TrimCache trimCache = new TrimCache(sbn);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c3f20af..b79caca 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -290,13 +290,14 @@
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
             String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
             @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
-            @Nullable String profileName) throws InstallerException {
+            @Nullable String profileName, @Nullable String dexMetadataPath)
+            throws InstallerException {
         assertValidInstructionSet(instructionSet);
         if (!checkBeforeRemote()) return;
         try {
             mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
                     dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
-                    targetSdkVersion, profileName);
+                    targetSdkVersion, profileName, dexMetadataPath);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 10e05cf..fc73142 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -261,12 +261,12 @@
                     String instructionSet, int dexoptNeeded, @Nullable String outputPath,
                     int dexFlags, String compilerFilter, @Nullable String volumeUuid,
                     @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
-                    int targetSdkVersion, @Nullable String profileName)
-                    throws InstallerException {
+                    int targetSdkVersion, @Nullable String profileName,
+                    @Nullable String dexMetadataPath) throws InstallerException {
                 final StringBuilder builder = new StringBuilder();
 
-                // The version. Right now it's 5.
-                builder.append("5 ");
+                // The version. Right now it's 6.
+                builder.append("6 ");
 
                 builder.append("dexopt");
 
@@ -284,6 +284,7 @@
                 encodeParameter(builder, downgrade);
                 encodeParameter(builder, targetSdkVersion);
                 encodeParameter(builder, profileName);
+                encodeParameter(builder, dexMetadataPath);
 
                 commands.add(builder.toString());
             }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index cde8cb7..2c68e67 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.dex.ArtManager;
+import android.content.pm.dex.DexMetadataHelper;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -209,6 +210,13 @@
 
             String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
 
+            String dexMetadataPath = null;
+            if (options.isDexoptInstallWithDexMetadata()) {
+                File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
+                dexMetadataPath = dexMetadataFile == null
+                        ? null : dexMetadataFile.getAbsolutePath();
+            }
+
             final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
                     || packageUseInfo.isUsedByOtherApps(path);
             final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
@@ -223,7 +231,7 @@
             for (String dexCodeIsa : dexCodeInstructionSets) {
                 int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
                         profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
-                        packageStats, options.isDowngrade(), profileName);
+                        packageStats, options.isDowngrade(), profileName, dexMetadataPath);
                 // The end result is:
                 //  - FAILED if any path failed,
                 //  - PERFORMED if at least one path needed compilation,
@@ -248,7 +256,7 @@
     private int dexOptPath(PackageParser.Package pkg, String path, String isa,
             String compilerFilter, boolean profileUpdated, String classLoaderContext,
             int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
-            String profileName) {
+            String profileName, String dexMetadataPath) {
         int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
                 profileUpdated, downgrade);
         if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -275,7 +283,7 @@
             mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
                     compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
                     false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
-                    profileName);
+                    profileName, dexMetadataPath);
 
             if (packageStats != null) {
                 long endTime = System.currentTimeMillis();
@@ -396,7 +404,8 @@
                 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                         /*oatDir*/ null, dexoptFlags,
                         compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
-                        options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null);
+                        options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null,
+                        /*dexMetadataPath*/ null);
             }
 
             return DEX_OPT_PERFORMED;
@@ -511,9 +520,13 @@
     private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
         int flags = info.flags;
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-        // Profile guide compiled oat files should not be public.
+        // Profile guide compiled oat files should not be public unles they are based
+        // on profiles from dex metadata archives.
+        // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
+        // the user does not have an existing profile.
         boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
-        boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
+        boolean isPublic = !info.isForwardLocked() &&
+                (!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata());
         int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
         // System apps are invoked with a runtime flag which exempts them from
         // restrictions on hidden API usage. We dexopt with the same runtime flag
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a6ff4f7..3dd5a34 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -77,6 +77,7 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.system.ErrnoException;
+import android.system.Int64Ref;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStat;
@@ -575,14 +576,24 @@
     @Override
     public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
         try {
-            return openWriteInternal(name, offsetBytes, lengthBytes);
+            return doWriteInternal(name, offsetBytes, lengthBytes, null);
         } catch (IOException e) {
             throw ExceptionUtils.wrap(e);
         }
     }
 
-    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
-            throws IOException {
+    @Override
+    public void write(String name, long offsetBytes, long lengthBytes,
+            ParcelFileDescriptor fd) {
+        try {
+            doWriteInternal(name, offsetBytes, lengthBytes, fd);
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
+    }
+
+    private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
+            ParcelFileDescriptor incomingFd) throws IOException {
         // Quick sanity check of state, and allocate a pipe for ourselves. We
         // then do heavy disk allocation outside the lock, but this open pipe
         // will block any attempted install transitions.
@@ -636,7 +647,44 @@
                 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
             }
 
-            if (PackageInstaller.ENABLE_REVOCABLE_FD) {
+            if (incomingFd != null) {
+                switch (Binder.getCallingUid()) {
+                    case android.os.Process.SHELL_UID:
+                    case android.os.Process.ROOT_UID:
+                        break;
+                    default:
+                        throw new SecurityException("Reverse mode only supported from shell");
+                }
+
+                // In "reverse" mode, we're streaming data ourselves from the
+                // incoming FD, which means we never have to hand out our
+                // sensitive internal FD. We still rely on a "bridge" being
+                // inserted above to hold the session active.
+                try {
+                    final Int64Ref last = new Int64Ref(0);
+                    FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
+                        if (params.sizeBytes > 0) {
+                            final long delta = progress - last.value;
+                            last.value = progress;
+                            addClientProgress((float) delta / (float) params.sizeBytes);
+                        }
+                    }, null, lengthBytes);
+                } finally {
+                    IoUtils.closeQuietly(targetFd);
+                    IoUtils.closeQuietly(incomingFd);
+
+                    // We're done here, so remove the "bridge" that was holding
+                    // the session active.
+                    synchronized (mLock) {
+                        if (PackageInstaller.ENABLE_REVOCABLE_FD) {
+                            mFds.remove(fd);
+                        } else {
+                            mBridges.remove(bridge);
+                        }
+                    }
+                }
+                return null;
+            } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
                 fd.init(mContext, targetFd);
                 return fd.getRevocableFileDescriptor();
             } else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89fbd17..a0cb722 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3840,10 +3840,6 @@
         if (ps == null) {
             return null;
         }
-        PackageParser.Package p = ps.pkg;
-        if (p == null) {
-            return null;
-        }
         final int callingUid = Binder.getCallingUid();
         // Filter out ephemeral app metadata:
         //   * The system/shell/root can see metadata for any app
@@ -3855,32 +3851,58 @@
             return null;
         }
 
-        final PermissionsState permissionsState = ps.getPermissionsState();
-
-        // Compute GIDs only if requested
-        final int[] gids = (flags & PackageManager.GET_GIDS) == 0
-                ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
-        // Compute granted permissions only if package has requested permissions
-        final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
-                ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
-        final PackageUserState state = ps.readUserState(userId);
-
         if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
                 && ps.isSystem()) {
             flags |= MATCH_ANY_USER;
         }
 
-        PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
-                ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+        final PackageUserState state = ps.readUserState(userId);
+        PackageParser.Package p = ps.pkg;
+        if (p != null) {
+            final PermissionsState permissionsState = ps.getPermissionsState();
 
-        if (packageInfo == null) {
+            // Compute GIDs only if requested
+            final int[] gids = (flags & PackageManager.GET_GIDS) == 0
+                    ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
+            // Compute granted permissions only if package has requested permissions
+            final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+                    ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
+
+            PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+                    ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+
+            if (packageInfo == null) {
+                return null;
+            }
+
+            packageInfo.packageName = packageInfo.applicationInfo.packageName =
+                    resolveExternalPackageNameLPr(p);
+
+            return packageInfo;
+        } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
+            PackageInfo pi = new PackageInfo();
+            pi.packageName = ps.name;
+            pi.setLongVersionCode(ps.versionCode);
+            pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
+            pi.firstInstallTime = ps.firstInstallTime;
+            pi.lastUpdateTime = ps.lastUpdateTime;
+
+            ApplicationInfo ai = new ApplicationInfo();
+            ai.packageName = ps.name;
+            ai.uid = UserHandle.getUid(userId, ps.appId);
+            ai.primaryCpuAbi = ps.primaryCpuAbiString;
+            ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
+            ai.versionCode = ps.versionCode;
+            ai.flags = ps.pkgFlags;
+            ai.privateFlags = ps.pkgPrivateFlags;
+            pi.applicationInfo = PackageParser.generateApplicationInfo(ai, flags, state, userId);
+
+            if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["
+                    + ps.name + "]. Provides a minimum info.");
+            return pi;
+        } else {
             return null;
         }
-
-        packageInfo.packageName = packageInfo.applicationInfo.packageName =
-                resolveExternalPackageNameLPr(p);
-
-        return packageInfo;
     }
 
     @Override
@@ -17309,7 +17331,8 @@
             // Also, don't fail application installs if the dexopt step fails.
             DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
                     REASON_INSTALL,
-                    DexoptOptions.DEXOPT_BOOT_COMPLETE);
+                    DexoptOptions.DEXOPT_BOOT_COMPLETE |
+                    DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
             mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
                     null /* instructionSets */,
                     getOrCreateCompilerPackageStats(pkg),
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 686c4a5..758c9d5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -16,6 +16,12 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+
 import android.accounts.IAccountManager;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -32,8 +38,10 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
@@ -41,9 +49,6 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionParams;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
@@ -73,7 +78,6 @@
 
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.SizedInputStream;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 
@@ -81,9 +85,8 @@
 
 import libcore.io.IoUtils;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -95,12 +98,6 @@
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-
 class PackageManagerShellCommand extends ShellCommand {
     /** Path for streaming APK content */
     private static final String STDIN_PATH = "-";
@@ -2213,7 +2210,7 @@
         final PrintWriter pw = getOutPrintWriter();
         final ParcelFileDescriptor fd;
         if (STDIN_PATH.equals(inPath)) {
-            fd = null;
+            fd = new ParcelFileDescriptor(getInFileDescriptor());
         } else if (inPath != null) {
             fd = openFileForSystem(inPath, "r");
             if (fd == null) {
@@ -2225,53 +2222,27 @@
                 return -1;
             }
         } else {
-            fd = null;
+            fd = new ParcelFileDescriptor(getInFileDescriptor());
         }
         if (sizeBytes <= 0) {
             getErrPrintWriter().println("Error: must specify a APK size");
             return 1;
         }
 
-        final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
-
         PackageInstaller.Session session = null;
-        InputStream in = null;
-        OutputStream out = null;
         try {
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
-
-            if (fd != null) {
-                in = new ParcelFileDescriptor.AutoCloseInputStream(fd);
-            } else {
-                in = new SizedInputStream(getRawInputStream(), sizeBytes);
-            }
-            out = session.openWrite(splitName, 0, sizeBytes);
-
-            int total = 0;
-            byte[] buffer = new byte[1024 * 1024];
-            int c;
-            while ((c = in.read(buffer)) != -1) {
-                total += c;
-                out.write(buffer, 0, c);
-
-                if (info.sizeBytes > 0) {
-                    final float fraction = ((float) c / (float) info.sizeBytes);
-                    session.addProgress(fraction);
-                }
-            }
-            session.fsync(out);
+            session.write(splitName, 0, sizeBytes, fd);
 
             if (logSuccess) {
-                pw.println("Success: streamed " + total + " bytes");
+                pw.println("Success: streamed " + sizeBytes + " bytes");
             }
             return 0;
         } catch (IOException e) {
             getErrPrintWriter().println("Error: failed to write; " + e.getMessage());
             return 1;
         } finally {
-            IoUtils.closeQuietly(out);
-            IoUtils.closeQuietly(in);
             IoUtils.closeQuietly(session);
         }
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ebf6672..e4c74ed 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -703,7 +703,7 @@
      */
     public boolean rescanPackageIfNeeded(boolean isNewApp, boolean forceRescan) {
         final ShortcutService s = mShortcutUser.mService;
-        final long start = s.injectElapsedRealtime();
+        final long start = s.getStatStartTime();
 
         final PackageInfo pi;
         try {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d2bc6d2..a85d6d8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -99,6 +99,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
+import com.android.server.StatLogger;
 import com.android.server.SystemService;
 import com.android.server.pm.ShortcutUser.PackageWithUser;
 
@@ -367,7 +368,7 @@
         int COUNT = GET_DEFAULT_LAUNCHER + 1;
     }
 
-    private static final String[] STAT_LABELS = {
+    private final StatLogger mStatLogger = new StatLogger(new String[] {
             "getHomeActivities()",
             "Launcher permission check",
             "getPackageInfo()",
@@ -385,15 +386,7 @@
             "packageUpdateCheck",
             "asyncPreloadUserDelay",
             "getDefaultLauncher()"
-    };
-
-    final Object mStatLock = new Object();
-
-    @GuardedBy("mStatLock")
-    private final int[] mCountStats = new int[Stats.COUNT];
-
-    @GuardedBy("mStatLock")
-    private final long[] mDurationStats = new long[Stats.COUNT];
+    });
 
     private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
             ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
@@ -480,11 +473,12 @@
                 | ActivityManager.UID_OBSERVER_GONE);
     }
 
+    long getStatStartTime() {
+        return mStatLogger.getTime();
+    }
+
     void logDurationStat(int statId, long start) {
-        synchronized (mStatLock) {
-            mCountStats[statId]++;
-            mDurationStats[statId] += (injectElapsedRealtime() - start);
-        }
+        mStatLogger.logDurationStat(statId, start);
     }
 
     public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
@@ -621,7 +615,7 @@
         // late since the launcher would already have started.
         // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
         // or anything.
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         injectRunOnNewThread(() -> {
             synchronized (mLock) {
                 logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
@@ -1289,7 +1283,7 @@
         if (DEBUG) {
             Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
         }
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
 
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
@@ -1485,7 +1479,7 @@
         final Resources publisherRes = injectGetResourcesForApplicationAsUser(
                 si.getPackage(), si.getUserId());
         if (publisherRes != null) {
-            final long start = injectElapsedRealtime();
+            final long start = getStatStartTime();
             try {
                 si.lookupAndFillInResourceNames(publisherRes);
             } finally {
@@ -2264,7 +2258,7 @@
         if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
             return true;
         }
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             return hasShortcutHostPermissionInner(callingPackage, userId);
         } finally {
@@ -2327,7 +2321,7 @@
 
     @Nullable
     ComponentName getDefaultLauncher(@UserIdInt int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             synchronized (mLock) {
@@ -2338,7 +2332,7 @@
                 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
 
                 // Default launcher from package manager.
-                final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
+                final long startGetHomeActivitiesAsUser = getStatStartTime();
                 final ComponentName defaultLauncher = mPackageManagerInternal
                         .getHomeActivitiesAsUser(allHomeCandidates, userId);
                 logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
@@ -2910,7 +2904,7 @@
             return;
         }
 
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
 
@@ -3087,7 +3081,7 @@
     @VisibleForTesting
     PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
             boolean getSignatures) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getPackageInfo(
@@ -3122,7 +3116,7 @@
     @VisibleForTesting
     ApplicationInfo injectApplicationInfoWithUninstalled(
             String packageName, @UserIdInt int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
@@ -3153,7 +3147,7 @@
     @VisibleForTesting
     ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(
             ComponentName activity, @UserIdInt int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getActivityInfo(activity,
@@ -3175,7 +3169,7 @@
     @NonNull
     @VisibleForTesting
     final List<PackageInfo> getInstalledPackages(@UserIdInt int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             final List<PackageInfo> all = injectGetPackagesWithUninstalled(userId);
@@ -3280,7 +3274,7 @@
 
     @Nullable
     Resources injectGetResourcesForApplicationAsUser(String packageName, int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
             return mContext.getPackageManager().getResourcesForApplicationAsUser(
@@ -3348,7 +3342,7 @@
      */
     @Nullable
     ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             final List<ResolveInfo> resolved =
                     queryActivities(getMainActivityIntent(), packageName, null, userId);
@@ -3362,7 +3356,7 @@
      * Return whether an activity is enabled, exported and main.
      */
     boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             if (activity == null) {
                 wtf("null activity detected");
@@ -3397,7 +3391,7 @@
      */
     @NonNull
     List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             return queryActivities(getMainActivityIntent(), packageName, null, userId);
         } finally {
@@ -3411,7 +3405,7 @@
     @VisibleForTesting
     boolean injectIsActivityEnabledAndExported(
             @NonNull ComponentName activity, @UserIdInt int userId) {
-        final long start = injectElapsedRealtime();
+        final long start = getStatStartTime();
         try {
             return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
                     .size() > 0;
@@ -3831,12 +3825,7 @@
                 pw.println(mMaxShortcuts);
                 pw.println();
 
-                pw.println("  Stats:");
-                synchronized (mStatLock) {
-                    for (int i = 0; i < Stats.COUNT; i++) {
-                        dumpStatLS(pw, "    ", i);
-                    }
-                }
+                mStatLogger.dump(pw, "  ");
 
                 pw.println();
                 pw.print("  #Failures: ");
@@ -3902,15 +3891,6 @@
         pw.print(formatTime(injectCurrentTimeMillis()));
     }
 
-    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
-        pw.print(prefix);
-        final int count = mCountStats[statId];
-        final long dur = mDurationStats[statId];
-        pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
-                STAT_LABELS[statId], count, dur,
-                (count == 0 ? 0 : ((double) dur) / count)));
-    }
-
     /**
      * Dumpsys for checkin.
      *
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 92fd904..b53d83b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -88,6 +88,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -387,7 +388,9 @@
             }
             final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
             final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
-            setQuietModeEnabled(userHandle, false, target);
+            // Call setQuietModeEnabled on bg thread to avoid ANR
+            BackgroundThread.getHandler()
+                    .post(() -> setQuietModeEnabled(userHandle, false, target));
         }
     };
 
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index a42fcbd..842f8d0 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -117,7 +117,7 @@
             UserManager.DISALLOW_AUTOFILL,
             UserManager.DISALLOW_USER_SWITCH,
             UserManager.DISALLOW_UNIFIED_PASSWORD,
-            UserManager.DISALLOW_CONFIG_LOCATION_MODE,
+            UserManager.DISALLOW_CONFIG_LOCATION,
             UserManager.DISALLOW_AIRPLANE_MODE,
             UserManager.DISALLOW_CONFIG_BRIGHTNESS,
             UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index 0966770..d4f95cb 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -59,6 +59,10 @@
     // When set, indicates that dexopt is invoked from the background service.
     public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
 
+    // When set, indicates that dexopt is invoked from the install time flow and
+    // should get the dex metdata file if present.
+    public static final int DEXOPT_INSTALL_WITH_DEX_METADATA_FILE = 1 << 10;
+
     // The name of package to optimize.
     private final String mPackageName;
 
@@ -90,7 +94,8 @@
                 DEXOPT_ONLY_SHARED_DEX |
                 DEXOPT_DOWNGRADE |
                 DEXOPT_AS_SHARED_LIBRARY |
-                DEXOPT_IDLE_BACKGROUND_JOB;
+                DEXOPT_IDLE_BACKGROUND_JOB |
+                DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
         if ((flags & (~validityMask)) != 0) {
             throw new IllegalArgumentException("Invalid flags : " + Integer.toHexString(flags));
         }
@@ -141,6 +146,10 @@
         return (mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
     }
 
+    public boolean isDexoptInstallWithDexMetadata() {
+        return (mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) != 0;
+    }
+
     public String getSplitName() {
         return mSplitName;
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0502848..177d6af 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5603,9 +5603,7 @@
         final int fl = PolicyControl.getWindowFlags(null,
                 mTopFullscreenOpaqueWindowState.getAttrs());
         if (localLOGV) {
-            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
-                    + " shown position: "
-                    + mTopFullscreenOpaqueWindowState.getShownPositionLw());
+            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
             Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                     + " lp.flags=0x" + Integer.toHexString(fl));
         }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e9c4c5c..3af3fcb 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -232,14 +232,6 @@
         public Rect getFrameLw();
 
         /**
-         * Retrieve the current position of the window that is actually shown.
-         * Must be called with the window manager lock held.
-         *
-         * @return Point The point holding the shown window position.
-         */
-        public Point getShownPositionLw();
-
-        /**
          * Retrieve the frame of the display that this window was last
          * laid out in.  Must be called with the
          * window manager lock held.
diff --git a/services/core/java/com/android/server/slice/SliceFullAccessList.java b/services/core/java/com/android/server/slice/SliceFullAccessList.java
index 5e0cd03..6f5afa2 100644
--- a/services/core/java/com/android/server/slice/SliceFullAccessList.java
+++ b/services/core/java/com/android/server/slice/SliceFullAccessList.java
@@ -16,9 +16,9 @@
 
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArraySet;
-import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.util.XmlUtils;
@@ -72,7 +72,7 @@
         pkgs.remove(pkg);
     }
 
-    public void writeXml(XmlSerializer out) throws IOException {
+    public void writeXml(XmlSerializer out, int user) throws IOException {
         out.startTag(null, TAG_LIST);
         out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
 
@@ -80,6 +80,9 @@
         for (int i = 0 ; i < N; i++) {
             final int userId = mFullAccessPkgs.keyAt(i);
             final ArraySet<String> pkgs = mFullAccessPkgs.valueAt(i);
+            if (user != UserHandle.USER_ALL && user != userId) {
+                continue;
+            }
             out.startTag(null, TAG_USER);
             out.attribute(null, ATT_USER_ID, Integer.toString(userId));
             if (pkgs != null) {
@@ -88,7 +91,6 @@
                         out.startTag(null, TAG_PKG);
                         out.text(pkgs.valueAt(j));
                         out.endTag(null, TAG_PKG);
-
                 }
             }
             out.endTag(null, TAG_USER);
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index c4871df..a1def44 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -21,6 +21,7 @@
 import static android.content.ContentProvider.maybeAddUserId;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Process.SYSTEM_UID;
 
 import android.Manifest.permission;
 import android.app.ActivityManager;
@@ -68,8 +69,9 @@
 import org.xmlpull.v1.XmlPullParserFactory;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -93,6 +95,7 @@
     private final ArraySet<SliceGrant> mUserGrants = new ArraySet<>();
     private final Handler mHandler;
     private final ContentObserver mObserver;
+    @GuardedBy("mSliceAccessFile")
     private final AtomicFile mSliceAccessFile;
     @GuardedBy("mAccessList")
     private final SliceFullAccessList mAccessList;
@@ -257,6 +260,63 @@
         }
     }
 
+    // Backup/restore interface
+    @Override
+    public byte[] getBackupPayload(int user) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
+            throw new SecurityException("Caller must be system");
+        }
+        //TODO: http://b/22388012
+        if (user != UserHandle.USER_SYSTEM) {
+            Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
+            return null;
+        }
+        synchronized(mSliceAccessFile) {
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            try {
+                XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
+                out.setOutput(baos, Encoding.UTF_8.name());
+                synchronized (mAccessList) {
+                    mAccessList.writeXml(out, user);
+                }
+                out.flush();
+                return baos.toByteArray();
+            } catch (IOException | XmlPullParserException e) {
+                Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void applyRestore(byte[] payload, int user) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
+            throw new SecurityException("Caller must be system");
+        }
+        if (payload == null) {
+            Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
+            return;
+        }
+        //TODO: http://b/22388012
+        if (user != UserHandle.USER_SYSTEM) {
+            Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
+            return;
+        }
+        synchronized(mSliceAccessFile) {
+            final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+            try {
+                XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+                parser.setInput(bais, Encoding.UTF_8.name());
+                synchronized (mAccessList) {
+                    mAccessList.readXml(parser);
+                }
+                mHandler.post(mSaveAccessList);
+            } catch (NumberFormatException | XmlPullParserException | IOException e) {
+                Slog.w(TAG, "applyRestore: error reading payload", e);
+            }
+        }
+    }
+
     ///  ----- internal code -----
     private void removeFullAccess(String pkg, int userId) {
         synchronized (mAccessList) {
@@ -492,7 +552,7 @@
                     XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
                     out.setOutput(stream, Encoding.UTF_8.name());
                     synchronized (mAccessList) {
-                        mAccessList.writeXml(out);
+                        mAccessList.writeXml(out, UserHandle.USER_ALL);
                     }
                     out.flush();
                     mSliceAccessFile.finishWrite(stream);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index adb368b..7c170ae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -56,7 +56,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-
 /**
  * A note on locking:  We rely on the fact that calls onto mBar are oneway or
  * if they are local, that they just enqueue messages to not deadlock.
@@ -525,6 +524,26 @@
     }
 
     @Override
+    public void showPinningEnterExitToast(boolean entering) throws RemoteException {
+        if (mBar != null) {
+            try {
+                mBar.showPinningEnterExitToast(entering);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void showPinningEscapeToast() throws RemoteException {
+        if (mBar != null) {
+            try {
+                mBar.showPinningEscapeToast();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
     public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
         if (mBar != null) {
             try {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index f09a294..2c3c5d2 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -55,6 +55,7 @@
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 
+import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
@@ -508,8 +509,14 @@
             // on-going notification for the user to control their visibility.
             if (visible) {
                 changed = mAlertWindowSurfaces.add(surfaceController);
+                if (changed) {
+                    MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, true);
+                }
             } else {
                 changed = mAlertWindowSurfaces.remove(surfaceController);
+                if (changed) {
+                    MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, true);
+                }
             }
 
             if (changed) {
@@ -530,8 +537,14 @@
 
         if (visible) {
             changed = mAppOverlaySurfaces.add(surfaceController);
+            if (changed) {
+                MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, false);
+            }
         } else {
             changed = mAppOverlaySurfaces.remove(surfaceController);
+            if (changed) {
+                MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, false);
+            }
         }
 
         if (changed) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 212a0d70..a7a2b53 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -27,6 +27,7 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.os.Environment;
@@ -40,6 +41,7 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
@@ -324,7 +326,8 @@
         if (mainWindow == null) {
             return null;
         }
-        final int color = task.getTaskDescription().getBackgroundColor();
+        final int color = ColorUtils.setAlphaComponent(
+                task.getTaskDescription().getBackgroundColor(), 255);
         final int statusBarColor = task.getTaskDescription().getStatusBarColor();
         final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
         final LayoutParams attrs = mainWindow.getAttrs();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 259f8df..e4db3b0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -47,6 +47,7 @@
 import android.app.ActivityThread;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -516,7 +517,7 @@
         @VisibleForTesting
         void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
                 int statusBarHeight) {
-            if (statusBarHeight > 0
+            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
                     && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
                 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
                         mContentInsets.right);
@@ -531,7 +532,7 @@
             getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
                     navigationBarRect);
             final boolean visible = isNavigationBarColorViewVisible();
-            if (visible && !navigationBarRect.isEmpty()) {
+            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
                 c.drawRect(navigationBarRect, mNavigationBarPaint);
             }
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index f2ad6fb..da3a035 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -272,6 +272,8 @@
     }
 
     boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
+        int xOffset = 0;
+        int yOffset = 0;
         boolean rawChanged = false;
         // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
         // match the behavior of most Launchers
@@ -283,11 +285,8 @@
         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetX;
         }
-        boolean changed = wallpaperWin.mXOffset != offset;
-        if (changed) {
-            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
-            wallpaperWin.mXOffset = offset;
-        }
+        xOffset = offset;
+
         if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
             wallpaperWin.mWallpaperX = wpx;
             wallpaperWin.mWallpaperXStep = wpxs;
@@ -301,17 +300,16 @@
         if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetY;
         }
-        if (wallpaperWin.mYOffset != offset) {
-            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
-            changed = true;
-            wallpaperWin.mYOffset = offset;
-        }
+        yOffset = offset;
+
         if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
             wallpaperWin.mWallpaperY = wpy;
             wallpaperWin.mWallpaperYStep = wpys;
             rawChanged = true;
         }
 
+        boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
+
         if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
                 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
             try {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 2ae5c7b..ddda027 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -74,10 +74,6 @@
         for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
             final WindowState wallpaper = mChildren.get(wallpaperNdx);
             if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
-                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
-                winAnimator.computeShownFrameLocked();
-                // No need to lay out the windows - we can just set the wallpaper position directly.
-                winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
                 // We only want to be synchronous with one wallpaper.
                 sync = false;
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a9f2e03..3bee1e8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -137,7 +137,6 @@
 import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
 import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
 import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
-import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION;
 import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
 import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
 import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
@@ -297,12 +296,6 @@
     private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
 
     /**
-     * Actual position of the surface shown on-screen (may be modified by animation). These are
-     * in the screen's coordinate space (WITH the compatibility scale applied).
-     */
-    final Point mShownPosition = new Point();
-
-    /**
      * Insets that determine the actually visible area.  These are in the application's
      * coordinate space (without compatibility scale applied).
      */
@@ -461,10 +454,6 @@
     int mWallpaperDisplayOffsetX = Integer.MIN_VALUE;
     int mWallpaperDisplayOffsetY = Integer.MIN_VALUE;
 
-    // Wallpaper windows: pixels offset based on above variables.
-    int mXOffset;
-    int mYOffset;
-
     /**
      * This is set after IWindowSession.relayout() has been called at
      * least once for the window.  It allows us to detect the situation
@@ -745,8 +734,6 @@
         mRequestedHeight = 0;
         mLastRequestedWidth = 0;
         mLastRequestedHeight = 0;
-        mXOffset = 0;
-        mYOffset = 0;
         mLayer = 0;
         mInputWindowHandle = new InputWindowHandle(
                 mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
@@ -1112,11 +1099,6 @@
     }
 
     @Override
-    public Point getShownPositionLw() {
-        return mShownPosition;
-    }
-
-    @Override
     public Rect getDisplayFrameLw() {
         return mDisplayFrame;
     }
@@ -3134,7 +3116,6 @@
         mContentInsets.writeToProto(proto, CONTENT_INSETS);
         mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
         mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
-        mShownPosition.writeToProto(proto, SHOWN_POSITION);
         mWinAnimator.writeToProto(proto, ANIMATOR);
         proto.write(ANIMATING_EXIT, mAnimatingExit);
         for (int i = 0; i < mChildren.size(); i++) {
@@ -3250,10 +3231,6 @@
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
                     pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
         }
-        if (mXOffset != 0 || mYOffset != 0) {
-            pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
-                    pw.print(" y="); pw.println(mYOffset);
-        }
         if (dumpAll) {
             pw.print(prefix); pw.print("mGivenContentInsets=");
                     mGivenContentInsets.printShortString(pw);
@@ -3272,7 +3249,6 @@
                     pw.println(getLastReportedConfiguration());
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
-                pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
                 pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
                 pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
         if (dumpAll) {
@@ -4195,9 +4171,8 @@
         final int width = mFrame.width();
         final int height = mFrame.height();
 
-        // Compute the offset of the window in relation to the decor rect.
-        final int left = mXOffset + mFrame.left;
-        final int top = mYOffset + mFrame.top;
+        final int left = mFrame.left;
+        final int top = mFrame.top;
 
         // Initialize the decor rect to the entire frame.
         if (isDockedResizing()) {
@@ -4392,8 +4367,8 @@
         float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
         float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
         float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
-        int x = mSurfacePosition.x + mShownPosition.x;
-        int y = mSurfacePosition.y + mShownPosition.y;
+        int x = mSurfacePosition.x;
+        int y = mSurfacePosition.y;
 
         // If changed, also adjust transformFrameToSurfacePosition
         final WindowContainer parent = getParent();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5c9cfbb..499322c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -209,6 +209,12 @@
     float mExtraHScale = (float) 1.0;
     float mExtraVScale = (float) 1.0;
 
+    // An offset in pixel of the surface contents from the window position. Used for Wallpaper
+    // to provide the effect of scrolling within a large surface. We just use these values as
+    // a cache.
+    int mXOffset = 0;
+    int mYOffset = 0;
+
     private final Rect mTmpSize = new Rect();
 
     WindowStateAnimator(final WindowState win) {
@@ -436,7 +442,7 @@
             flags |= SurfaceControl.SECURE;
         }
 
-        mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
+        mTmpSize.set(0, 0, 0, 0);
         calculateSurfaceBounds(w, attrs);
         final int width = mTmpSize.width();
         final int height = mTmpSize.height();
@@ -677,8 +683,8 @@
 
             // WindowState.prepareSurfaces expands for surface insets (in order they don't get
             // clipped by the WindowState surface), so we need to go into the other direction here.
-            tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
-                    mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
+            tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
+                    mWin.mAttrs.surfaceInsets.top);
 
 
             // "convert" it into SurfaceFlinger's format
@@ -693,9 +699,6 @@
             mDtDx = tmpFloats[Matrix.MSKEW_Y];
             mDtDy = tmpFloats[Matrix.MSKEW_X];
             mDsDy = tmpFloats[Matrix.MSCALE_Y];
-            float x = tmpFloats[Matrix.MTRANS_X];
-            float y = tmpFloats[Matrix.MTRANS_Y];
-            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             // Now set the alpha...  but because our current hardware
             // can't do alpha transformation on a non-opaque surface,
@@ -705,8 +708,7 @@
             mShownAlpha = mAlpha;
             if (!mService.mLimitedAlphaCompositing
                     || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
-                    || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
-                            && x == frame.left && y == frame.top))) {
+                    || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
                 //Slog.i(TAG_WM, "Applying alpha transform");
                 if (screenAnimation) {
                     mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
@@ -736,10 +738,6 @@
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
 
-        // WindowState.prepareSurfaces expands for surface insets (in order they don't get
-        // clipped by the WindowState surface), so we need to go into the other direction here.
-        mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
-                mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
         mShownAlpha = mAlpha;
         mHaveMatrix = false;
         mDsDx = mWin.mGlobalScale;
@@ -790,12 +788,6 @@
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
                 + " fullscreen=" + fullscreen);
 
-        if (isFreeformResizing && !w.isChildWindow()) {
-            // For freeform resizing non child windows, we are using the big surface positioned
-            // at 0,0. Thus we must express the crop in that coordinate space.
-            clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
-        }
-
         w.expandForSurfaceInsets(clipRect);
 
         // The clip rect was generated assuming (0,0) as the window origin,
@@ -837,7 +829,7 @@
             return;
         }
 
-        mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
+        mTmpSize.set(0, 0, 0, 0);
         calculateSurfaceBounds(w, attrs);
 
         mExtraHScale = (float) 1.0;
@@ -971,11 +963,6 @@
             // then take over the scaling until the new buffer arrives, and things
             // will be seamless.
             mForceScaleUntilResize = true;
-        } else {
-            if (!w.mSeamlesslyRotated) {
-                mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
-                        recoveringMemory);
-            }
         }
 
         // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
@@ -1167,24 +1154,26 @@
         mSurfaceController.setTransparentRegionHint(region);
     }
 
-    void setWallpaperOffset(Point shownPosition) {
-        final LayoutParams attrs = mWin.getAttrs();
-        final int left = shownPosition.x - attrs.surfaceInsets.left;
-        final int top = shownPosition.y - attrs.surfaceInsets.top;
+    boolean setWallpaperOffset(int dx, int dy) {
+        if (mXOffset == dx && mYOffset == dy) {
+            return false;
+        }
+        mXOffset = dx;
+        mYOffset = dy;
 
         try {
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
             mService.openSurfaceTransaction();
-            mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
-                    mWin.mFrame.top + top, false);
+            mSurfaceController.setPositionInTransaction(dx, dy, false);
             applyCrop(null, false);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error positioning surface of " + mWin
-                    + " pos=(" + left + "," + top + ")", e);
+                    + " pos=(" + dx + "," + dy + ")", e);
         } finally {
             mService.closeSurfaceTransaction("setWallpaperOffset");
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setWallpaperOffset");
+            return true;
         }
     }
 
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 8c38e0a..847222a 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -395,7 +395,8 @@
             gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId,
             jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners,
             prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported,
-            jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), jVendorInfo.get()));
+            jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), nullptr,
+            jVendorInfo.get()));
 }
 
 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties,
@@ -712,7 +713,7 @@
     gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
             "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
             "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
-            "[I[ILjava/util/Map;)V");
+            "[I[ILjava/util/Map;Ljava/util/Map;)V");
 
     auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
     gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 210fd47..d5ed98e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -723,21 +723,9 @@
         MmsServiceBroker mmsService = null;
         HardwarePropertiesManagerService hardwarePropertiesService = null;
 
-        boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
         boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
-        boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
-                false);
-        boolean disableSerial = SystemProperties.getBoolean("config.disable_serial", false);
-        boolean disableSearchManager = SystemProperties.getBoolean("config.disable_searchmanager",
-                false);
-        boolean disableTrustManager = SystemProperties.getBoolean("config.disable_trustmanager",
-                false);
-        boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices",
-                false);
         boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                 "config.disable_systemtextclassifier", false);
-        boolean disableConsumerIr = SystemProperties.getBoolean("config.disable_consumerir", false);
-        boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false);
         boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
                 false);
         boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
@@ -745,6 +733,9 @@
 
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
+        boolean isWatch = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WATCH);
+
         // For debugging RescueParty
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
             throw new RuntimeException();
@@ -819,7 +810,7 @@
             ServiceManager.addService("vibrator", vibrator);
             traceEnd();
 
-            if (!disableConsumerIr) {
+            if (!isWatch) {
                 traceBeginAndSlog("StartConsumerIrService");
                 consumerIr = new ConsumerIrService(context);
                 ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
@@ -862,7 +853,7 @@
                 traceLog.traceEnd();
             }, START_HIDL_SERVICES);
 
-            if (!disableVrManager) {
+            if (!isWatch) {
                 traceBeginAndSlog("StartVrManagerService");
                 mSystemServiceManager.startService(VrManagerService.class);
                 traceEnd();
@@ -1030,7 +1021,7 @@
             mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
             traceEnd();
 
-            if (!disableSystemUI) {
+            if (!isWatch) {
                 traceBeginAndSlog("StartStatusBarManagerService");
                 try {
                     statusBar = new StatusBarManagerService(context, wm);
@@ -1063,11 +1054,9 @@
             }
             traceEnd();
 
-            if (!disableTextServices) {
-                traceBeginAndSlog("StartTextServicesManager");
-                mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
-                traceEnd();
-            }
+            traceBeginAndSlog("StartTextServicesManager");
+            mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
+            traceEnd();
 
             if (!disableSystemTextClassifier) {
                 traceBeginAndSlog("StartTextClassificationManagerService");
@@ -1229,7 +1218,7 @@
             }
             traceEnd();
 
-            if (!disableSearchManager) {
+            if (!isWatch) {
                 traceBeginAndSlog("StartSearchManagerService");
                 try {
                     mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
@@ -1259,7 +1248,7 @@
             mSystemServiceManager.startService(DockObserver.class);
             traceEnd();
 
-            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            if (isWatch) {
                 traceBeginAndSlog("StartThermalObserver");
                 mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
                 traceEnd();
@@ -1291,7 +1280,7 @@
                 traceEnd();
             }
 
-            if (!disableSerial) {
+            if (!isWatch) {
                 traceBeginAndSlog("StartSerialService");
                 try {
                     // Serial port support
@@ -1331,11 +1320,9 @@
             mSystemServiceManager.startService(SoundTriggerService.class);
             traceEnd();
 
-            if (!disableTrustManager) {
-                traceBeginAndSlog("StartTrustManager");
-                mSystemServiceManager.startService(TrustManagerService.class);
-                traceEnd();
-            }
+            traceBeginAndSlog("StartTrustManager");
+            mSystemServiceManager.startService(TrustManagerService.class);
+            traceEnd();
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
                 traceBeginAndSlog("StartBackupManager");
@@ -1392,14 +1379,16 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("StartNetworkTimeUpdateService");
-            try {
-                networkTimeUpdater = new NetworkTimeUpdateService(context);
-                ServiceManager.addService("network_time_update_service", networkTimeUpdater);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkTimeUpdate service", e);
+            if (!isWatch) {
+                traceBeginAndSlog("StartNetworkTimeUpdateService");
+                try {
+                    networkTimeUpdater = new NetworkTimeUpdateService(context);
+                    ServiceManager.addService("network_time_update_service", networkTimeUpdater);
+                } catch (Throwable e) {
+                    reportWtf("starting NetworkTimeUpdate service", e);
+                }
+                traceEnd();
             }
-            traceEnd();
 
             traceBeginAndSlog("StartCommonTimeManagementService");
             try {
@@ -1535,13 +1524,13 @@
             traceEnd();
         }
 
-        if (!disableMediaProjection) {
+        if (!isWatch) {
             traceBeginAndSlog("StartMediaProjectionManager");
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
             traceEnd();
         }
 
-        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+        if (isWatch) {
             traceBeginAndSlog("StartWearConnectivityService");
             mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
             traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index a16f118..2c50f22 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -54,7 +54,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -64,7 +63,6 @@
 
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
-import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.ForceAppStandbyTracker.Listener;
 
 import org.junit.Before;
@@ -83,6 +81,12 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
+/**
+ * Tests for {@link ForceAppStandbyTracker}
+ *
+ * Run with:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ForceAppStandbyTrackerTest {
@@ -236,7 +240,8 @@
         verify(mMockIActivityManager).registerUidObserver(
                 uidObserverArgumentCaptor.capture(),
                 eq(ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
-                        | ActivityManager.UID_OBSERVER_ACTIVE),
+                        | ActivityManager.UID_OBSERVER_ACTIVE
+                        | ActivityManager.UID_OBSERVER_PROCSTATE),
                 eq(ActivityManager.PROCESS_STATE_UNKNOWN),
                 isNull());
         verify(mMockIAppOpsService).startWatchingMode(
@@ -333,23 +338,23 @@
         mPowerSaveMode = true;
         mPowerSaveObserver.accept(getPowerSaveState());
 
-        assertFalse(instance.isInForeground(UID_1));
-        assertFalse(instance.isInForeground(UID_2));
-        assertTrue(instance.isInForeground(Process.SYSTEM_UID));
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
         mIUidObserver.onUidActive(UID_1);
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
-        assertTrue(instance.isInForeground(UID_1));
-        assertFalse(instance.isInForeground(UID_2));
+        assertTrue(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
 
         mIUidObserver.onUidGone(UID_1, /*disable=*/ false);
         areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
-        assertFalse(instance.isInForeground(UID_1));
-        assertFalse(instance.isInForeground(UID_2));
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
 
         mIUidObserver.onUidActive(UID_1);
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
@@ -360,8 +365,8 @@
         areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
-        assertFalse(instance.isInForeground(UID_1));
-        assertFalse(instance.isInForeground(UID_2));
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
 
         // Toggle the app ops.
         mPowerSaveMode = false;
@@ -456,6 +461,88 @@
     }
 
     @Test
+    public void testUidStateForeground() throws Exception {
+        final ForceAppStandbyTrackerTestable instance = newInstance();
+        callStart(instance);
+
+        mIUidObserver.onUidActive(UID_1);
+
+        assertTrue(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+
+        mIUidObserver.onUidStateChanged(UID_2,
+                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0);
+
+        assertTrue(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertTrue(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+
+        mIUidObserver.onUidStateChanged(UID_1,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+
+        assertTrue(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertTrue(instance.isUidInForeground(UID_1));
+        assertTrue(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        mIUidObserver.onUidGone(UID_1, true);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertTrue(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        mIUidObserver.onUidIdle(UID_2, true);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        mIUidObserver.onUidStateChanged(UID_1,
+                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertTrue(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        mIUidObserver.onUidStateChanged(UID_1,
+                ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+    }
+
+    @Test
     public void testExempt() throws Exception {
         final ForceAppStandbyTrackerTestable instance = newInstance();
         callStart(instance);
@@ -953,8 +1040,8 @@
         setAppOps(UID_2, PACKAGE_2, true);
         setAppOps(UID_10_2, PACKAGE_2, true);
 
-        assertTrue(instance.isInForeground(UID_1));
-        assertTrue(instance.isInForeground(UID_10_1));
+        assertTrue(instance.isUidActive(UID_1));
+        assertTrue(instance.isUidActive(UID_10_1));
 
         assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
         assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
@@ -965,8 +1052,8 @@
 
         waitUntilMainHandlerDrain();
 
-        assertTrue(instance.isInForeground(UID_1));
-        assertFalse(instance.isInForeground(UID_10_1));
+        assertTrue(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_10_1));
 
         assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
         assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
index d2ae22b..1cbb399 100644
--- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
@@ -90,7 +90,6 @@
     @Mock private IStatusBarService mStatusBarService;
     @Mock private WindowManagerService mWindowManager;
     @Mock private LockPatternUtils mLockPatternUtils;
-    @Mock private LockTaskNotify mLockTaskNotify;
     @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
     @Mock private TelecomManager mTelecomManager;
     @Mock private RecentTasks mRecentTasks;
@@ -123,7 +122,6 @@
         mLockTaskController.mDevicePolicyManager = mDevicePolicyManager;
         mLockTaskController.mTelecomManager = mTelecomManager;
         mLockTaskController.mLockPatternUtils = mLockPatternUtils;
-        mLockTaskController.mLockTaskNotify = mLockTaskNotify;
 
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
         LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
@@ -208,7 +206,7 @@
         // THEN lock task mode should be started
         verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE);
         // THEN screen pinning toast should be shown
-        verify(mLockTaskNotify).showPinningStartToast();
+        verify(mStatusBarService).showPinningEnterExitToast(true /* entering */);
     }
 
     @Test
@@ -377,7 +375,7 @@
         // THEN the keyguard should be shown
         verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
         // THEN screen pinning toast should be shown
-        verify(mLockTaskNotify).showPinningExitToast();
+        verify(mStatusBarService).showPinningEnterExitToast(false /* entering */);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index c863aab..473a813 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -39,6 +39,7 @@
 import android.os.Binder;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
+import android.security.KeyStore;
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
@@ -49,6 +50,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
@@ -135,6 +137,8 @@
     @Mock private RecoverySnapshotListenersStorage mMockListenersStorage;
     @Mock private KeyguardManager mKeyguardManager;
     @Mock private PlatformKeyManager mPlatformKeyManager;
+    @Mock private KeyStore mKeyStore;
+    @Mock private ApplicationKeyStorage mApplicationKeyStorage;
 
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
     private File mDatabaseFile;
@@ -164,12 +168,14 @@
 
         mRecoverableKeyStoreManager = new RecoverableKeyStoreManager(
                 mMockContext,
+                mKeyStore,
                 mRecoverableKeyStoreDb,
                 mRecoverySessionStorage,
                 Executors.newSingleThreadExecutor(),
                 mRecoverySnapshotStorage,
                 mMockListenersStorage,
-                mPlatformKeyManager);
+                mPlatformKeyManager,
+                mApplicationKeyStorage);
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 56d4b7e..857925b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -5149,7 +5149,8 @@
                     .forAllShortcuts(si -> {
                         switch (package1DisabledReason) {
                             case ShortcutInfo.DISABLED_REASON_VERSION_LOWER:
-                                assertEquals("This shortcut requires latest app",
+                                assertEquals("App version downgraded, or isn’t compatible"
+                                        + " with this shortcut",
                                         si.getDisabledMessage());
                                 break;
                             case ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH:
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index c2072df..f559986a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -53,6 +53,7 @@
         assertFalse(opt.isDowngrade());
         assertFalse(opt.isForce());
         assertFalse(opt.isDexoptIdleBackgroundJob());
+        assertFalse(opt.isDexoptInstallWithDexMetadata());
     }
 
     @Test
@@ -65,7 +66,8 @@
                 DexoptOptions.DEXOPT_ONLY_SHARED_DEX |
                 DexoptOptions.DEXOPT_DOWNGRADE  |
                 DexoptOptions.DEXOPT_AS_SHARED_LIBRARY |
-                DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
+                DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB |
+                DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
 
         DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, flags);
         assertEquals(mPackageName, opt.getPackageName());
@@ -79,6 +81,7 @@
         assertTrue(opt.isForce());
         assertTrue(opt.isDexoptAsSharedLibrary());
         assertTrue(opt.isDexoptIdleBackgroundJob());
+        assertTrue(opt.isDexoptInstallWithDexMetadata());
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index a628b7b..5de393c 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -79,11 +79,6 @@
     }
 
     @Override
-    public Point getShownPositionLw() {
-        return new Point(parentFrame.left, parentFrame.top);
-    }
-
-    @Override
     public Rect getDisplayFrameLw() {
         return displayFrame;
     }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 40964c0..78b6077 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -24,6 +24,7 @@
 import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_USAGE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -35,6 +36,7 @@
 import static org.junit.Assert.assertTrue;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
@@ -80,6 +82,8 @@
 
     private static final String PACKAGE_1 = "com.example.foo";
     private static final int UID_1 = 10000;
+    private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
+    private static final int UID_EXEMPTED_1 = 10001;
     private static final int USER_ID = 0;
     private static final int USER_ID2 = 10;
 
@@ -116,7 +120,7 @@
         List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
         boolean mDisplayOn;
         DisplayManager.DisplayListener mDisplayListener;
-        String mBoundWidgetPackage;
+        String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
 
         MyInjector(Context context, Looper looper) {
             super(context, looper);
@@ -223,10 +227,21 @@
         pi.packageName = PACKAGE_1;
         packages.add(pi);
 
+        PackageInfo pie = new PackageInfo();
+        pie.applicationInfo = new ApplicationInfo();
+        pie.applicationInfo.uid = UID_EXEMPTED_1;
+        pie.packageName = PACKAGE_EXEMPTED_1;
+        packages.add(pie);
+
         doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
         try {
-            doReturn(UID_1).when(mockPm).getPackageUidAsUser(anyString(), anyInt(), anyInt());
-            doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(anyString(), anyInt());
+            doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
+            doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
+                    anyInt(), anyInt());
+            doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
+                    anyInt());
+            doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
+                    anyInt());
         } catch (PackageManager.NameNotFoundException nnfe) {}
     }
 
@@ -239,14 +254,21 @@
 
     private AppStandbyController setupController() throws Exception {
         mInjector.mElapsedRealtime = 0;
+        setupPm(mInjector.getContext().getPackageManager());
         AppStandbyController controller = new AppStandbyController(mInjector);
+        controller.initializeDefaultsForSystemApps(USER_ID);
         controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
         mInjector.setDisplayOn(false);
         mInjector.setDisplayOn(true);
         setChargingState(controller, false);
-        setupPm(mInjector.getContext().getPackageManager());
         controller.checkIdleStates(USER_ID);
+        assertEquals(STANDBY_BUCKET_EXEMPTED,
+                controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
+        assertNotEquals(STANDBY_BUCKET_EXEMPTED,
+                controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
 
         return controller;
     }
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 99eb846..e36586e 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -210,6 +210,9 @@
         runCommand(instrumentation, "cmd package set-home-activity --user "
                 + instrumentation.getContext().getUserId() + " " + component,
                 result -> result.contains("Success"));
+        runCommand(instrumentation, "cmd shortcut clear-default-launcher --user "
+                        + instrumentation.getContext().getUserId(),
+                result -> result.contains("Success"));
     }
 
     public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9ae6f00..6b6df29 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -117,7 +117,7 @@
 public class NotificationManagerServiceTest extends UiServiceTestCase {
     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
     private final int mUid = Binder.getCallingUid();
-    private NotificationManagerService mService;
+    private TestableNotificationManagerService mService;
     private INotificationManager mBinderService;
     private NotificationManagerInternal mInternalService;
     @Mock
@@ -152,17 +152,21 @@
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
+        int countSystemChecks = 0;
+
         public TestableNotificationManagerService(Context context) {
             super(context);
         }
 
         @Override
         protected boolean isCallingUidSystem() {
+            countSystemChecks++;
             return true;
         }
 
         @Override
         protected boolean isCallerSystemOrPhone() {
+            countSystemChecks++;
             return true;
         }
 
@@ -2429,4 +2433,18 @@
                         .setUid(user2.sbn.getUid())
                         .setLastNotified(user2.sbn.getPostTime())));
     }
+
+    @Test
+    public void testRestore() throws Exception {
+        int systemChecks = mService.countSystemChecks;
+        mBinderService.applyRestore(null, UserHandle.USER_SYSTEM);
+        assertEquals(1, mService.countSystemChecks - systemChecks);
+    }
+
+    @Test
+    public void testBackup() throws Exception {
+        int systemChecks = mService.countSystemChecks;
+        mBinderService.getBackupPayload(1);
+        assertEquals(1, mService.countSystemChecks - systemChecks);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
index b784c60..bc28150 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
 import android.util.Xml.Encoding;
 
@@ -85,7 +86,7 @@
         ByteArrayOutputStream output = new ByteArrayOutputStream();
         XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
         out.setOutput(output, Encoding.UTF_8.name());
-        mAccessList.writeXml(out);
+        mAccessList.writeXml(out, UserHandle.USER_ALL);
         out.flush();
 
         assertEquals(TEST_XML, output.toString(Encoding.UTF_8.name()));
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 2becdf2..b654a66 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -228,7 +228,9 @@
             }
             if (timeout > elapsedRealtime) {
                 // Convert to elapsed timebase
-                appUsageHistory.bucketTimeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+                appUsageHistory.bucketTimeoutTime =
+                        Math.max(appUsageHistory.bucketTimeoutTime,
+                                mElapsedDuration + (timeout - mElapsedSnapshot));
             }
         }
         appUsageHistory.bucketingReason = REASON_USAGE;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 8cb2eec..cc21199 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -183,6 +183,8 @@
     boolean mCharging;
     private long mLastAppIdleParoledTime;
     private boolean mSystemServicesReady = false;
+    // There was a system update, defaults need to be initialized after services are ready
+    private boolean mPendingInitializeDefaults;
 
     private final DeviceStateReceiver mDeviceStateReceiver;
 
@@ -279,6 +281,7 @@
     public void onBootPhase(int phase) {
         mInjector.onBootPhase(phase);
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            Slog.d(TAG, "Setting app idle enabled state");
             setAppIdleEnabled(mInjector.isAppIdleEnabled());
             // Observe changes to the threshold
             SettingsObserver settingsObserver = new SettingsObserver(mHandler);
@@ -293,11 +296,15 @@
                 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
             }
 
+            mSystemServicesReady = true;
+
+            if (mPendingInitializeDefaults) {
+                initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
+            }
+
             if (mPendingOneTimeCheckIdleStates) {
                 postOneTimeCheckIdleStates();
             }
-
-            mSystemServicesReady = true;
         } else if (phase == PHASE_BOOT_COMPLETED) {
             setChargingState(mInjector.isCharging());
         }
@@ -451,7 +458,8 @@
                         UserHandle.getAppId(pi.applicationInfo.uid),
                         userId);
                 if (DEBUG) {
-                    Slog.d(TAG, "   Checking idle state for " + packageName);
+                    Slog.d(TAG, "   Checking idle state for " + packageName + " special=" +
+                            isSpecial);
                 }
                 if (isSpecial) {
                     synchronized (mAppIdleLock) {
@@ -523,6 +531,7 @@
                     elapsedRealtime, bucket)) {
                 StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
                         bucket, userStartedInteracting);
+                if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                         StandbyUpdateRecord.obtain(packageName, userId,
                                 bucket, userStartedInteracting)));
@@ -1087,7 +1096,13 @@
     }
 
     void initializeDefaultsForSystemApps(int userId) {
-        Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
+        if (!mSystemServicesReady) {
+            // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
+            mPendingInitializeDefaults = true;
+            return;
+        }
+        Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
+                + "appIdleEnabled=" + mAppIdleEnabled);
         final long elapsedRealtime = mInjector.elapsedRealtime();
         List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
                 PackageManager.MATCH_DISABLED_COMPONENTS,
@@ -1102,11 +1117,6 @@
                     // past usage pattern was.
                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
                             elapsedRealtime + 4 * ONE_HOUR);
-                    if (isAppSpecial(packageName, UserHandle.getAppId(pi.applicationInfo.uid),
-                            userId)) {
-                        mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
-                                STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
-                    }
                 }
             }
         }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
new file mode 100644
index 0000000..74280ff
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+/**
+ * Represents the ALSA specification, and attributes of an ALSA device.
+ */
+public final class UsbAlsaDevice {
+    private static final String TAG = "UsbAlsaDevice";
+    protected static final boolean DEBUG = false;
+
+    private final int mCardNum;
+    private final int mDeviceNum;
+    private final boolean mHasPlayback;
+    private final boolean mHasCapture;
+
+    private final boolean mIsInputHeadset;
+    private final boolean mIsOutputHeadset;
+
+    private final String mDeviceAddress;
+
+    private String mDeviceName = "";
+    private String mDeviceDescription = "";
+
+    public UsbAlsaDevice(int card, int device, String deviceAddress,
+            boolean hasPlayback, boolean hasCapture,
+            boolean isInputHeadset, boolean isOutputHeadset) {
+        mCardNum = card;
+        mDeviceNum = device;
+        mDeviceAddress = deviceAddress;
+        mHasPlayback = hasPlayback;
+        mHasCapture = hasCapture;
+        mIsInputHeadset = isInputHeadset;
+        mIsOutputHeadset = isOutputHeadset;
+    }
+
+    /**
+     * @returns the ALSA card number associated with this peripheral.
+     */
+    public int getCardNum() {
+        return mCardNum;
+    }
+
+    /**
+     * @returns the ALSA device number associated with this peripheral.
+     */
+    public int getDeviceNum() {
+        return mDeviceNum;
+    }
+
+    /**
+     * @returns the USB device device address associated with this peripheral.
+     */
+    public String getDeviceAddress() {
+        return mDeviceAddress;
+    }
+
+    /**
+     * @returns true if the device supports playback.
+     */
+    public boolean hasPlayback() {
+        return mHasPlayback;
+    }
+
+    /**
+     * @returns true if the device supports capture (recording).
+     */
+    public boolean hasCapture() {
+        return mHasCapture;
+    }
+
+    /**
+     * @returns true if the device is a headset for purposes of capture.
+     */
+    public boolean isInputHeadset() {
+        return mIsInputHeadset;
+    }
+
+    /**
+     * @returns true if the device is a headset for purposes of playback.
+     */
+    public boolean isOutputHeadset() {
+        return mIsOutputHeadset;
+    }
+
+    /**
+     * @Override
+     * @returns a string representation of the object.
+     */
+    public String toString() {
+        return "UsbAlsaDevice: [card: " + mCardNum
+            + ", device: " + mDeviceNum
+            + ", name: " + mDeviceName
+            + ", hasPlayback: " + mHasPlayback
+            + ", hasCapture: " + mHasCapture + "]";
+    }
+
+    // called by logDevices
+    String toShortString() {
+        return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
+    }
+
+    String getDeviceName() {
+        return mDeviceName;
+    }
+
+    void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
+        mDeviceName = deviceName;
+        mDeviceDescription = deviceDescription;
+    }
+
+    /**
+     * @Override
+     * @returns true if the objects are equivalent.
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof UsbAlsaDevice)) {
+            return false;
+        }
+        UsbAlsaDevice other = (UsbAlsaDevice) obj;
+        return (mCardNum == other.mCardNum
+                && mDeviceNum == other.mDeviceNum
+                && mHasPlayback == other.mHasPlayback
+                && mHasCapture == other.mHasCapture
+                && mIsInputHeadset == other.mIsInputHeadset
+                && mIsOutputHeadset == other.mIsOutputHeadset);
+    }
+
+    /**
+     * @Override
+     * @returns a hash code generated from the object contents.
+     */
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mCardNum;
+        result = prime * result + mDeviceNum;
+        result = prime * result + (mHasPlayback ? 0 : 1);
+        result = prime * result + (mHasCapture ? 0 : 1);
+        result = prime * result + (mIsInputHeadset ? 0 : 1);
+        result = prime * result + (mIsOutputHeadset ? 0 : 1);
+
+        return result;
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 7bea8a1..0a94828 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -10,7 +10,7 @@
  * 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 an
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -19,28 +19,24 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.midi.MidiDeviceInfo;
 import android.os.Bundle;
-import android.os.FileObserver;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.Slog;
 
 import com.android.internal.alsa.AlsaCardsParser;
-import com.android.internal.alsa.AlsaDevicesParser;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.audio.AudioService;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 import libcore.io.IoUtils;
 
-import java.io.File;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 /**
@@ -57,107 +53,36 @@
     private final boolean mHasMidiFeature;
 
     private final AlsaCardsParser mCardsParser = new AlsaCardsParser();
-    private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser();
 
     // this is needed to map USB devices to ALSA Audio Devices, especially to remove an
     // ALSA device when we are notified that its associated USB device has been removed.
+    private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
 
-    private final HashMap<UsbDevice,UsbAudioDevice>
-        mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();
-
-    private boolean mIsInputHeadset; // as reported by UsbDescriptorParser
-    private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser
-
-    private final HashMap<UsbDevice,UsbMidiDevice>
-        mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();
-
-    private final HashMap<String,AlsaDevice>
-        mAlsaDevices = new HashMap<String,AlsaDevice>();
-
-    private UsbAudioDevice mAccessoryAudioDevice = null;
+    /**
+     * List of connected MIDI devices
+     */
+    private final HashMap<String, UsbMidiDevice>
+            mMidiDevices = new HashMap<String, UsbMidiDevice>();
 
     // UsbMidiDevice for USB peripheral mode (gadget) device
     private UsbMidiDevice mPeripheralMidiDevice = null;
 
-    private final class AlsaDevice {
-        public static final int TYPE_UNKNOWN = 0;
-        public static final int TYPE_PLAYBACK = 1;
-        public static final int TYPE_CAPTURE = 2;
-        public static final int TYPE_MIDI = 3;
-
-        public int mCard;
-        public int mDevice;
-        public int mType;
-
-        public AlsaDevice(int type, int card, int device) {
-            mType = type;
-            mCard = card;
-            mDevice = device;
-        }
-
-        public boolean equals(Object obj) {
-            if (! (obj instanceof AlsaDevice)) {
-                return false;
-            }
-            AlsaDevice other = (AlsaDevice)obj;
-            return (mType == other.mType && mCard == other.mCard && mDevice == other.mDevice);
-        }
-
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("AlsaDevice: [card: " + mCard);
-            sb.append(", device: " + mDevice);
-            sb.append(", type: " + mType);
-            sb.append("]");
-            return sb.toString();
-        }
-    }
-
-    private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,
-            FileObserver.CREATE | FileObserver.DELETE) {
-        public void onEvent(int event, String path) {
-            switch (event) {
-                case FileObserver.CREATE:
-                    alsaFileAdded(path);
-                    break;
-                case FileObserver.DELETE:
-                    alsaFileRemoved(path);
-                    break;
-            }
-        }
-    };
-
     /* package */ UsbAlsaManager(Context context) {
         mContext = context;
         mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
-
-        // initial scan
-        if (mCardsParser.scan() != AlsaCardsParser.SCANSTATUS_SUCCESS) {
-            Slog.e(TAG, "Error scanning ASLA cards file.");
-        }
     }
 
     public void systemReady() {
         mAudioService = IAudioService.Stub.asInterface(
                         ServiceManager.getService(Context.AUDIO_SERVICE));
-
-        mAlsaObserver.startWatching();
-
-        // add existing alsa devices
-        File[] files = new File(ALSA_DIRECTORY).listFiles();
-        if (files != null) {
-            for (int i = 0; i < files.length; i++) {
-                alsaFileAdded(files[i].getName());
-            }
-        }
     }
 
     // Notifies AudioService when a device is added or removed
     // audioDevice - the AudioDevice that was added or removed
     // enabled - if true, we're connecting a device (it's arrived), else disconnecting
-    private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
+    private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) {
         if (DEBUG) {
-            Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
+            Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice);
         }
 
         if (mAudioService == null) {
@@ -177,276 +102,151 @@
         }
 
         int state = (enabled ? 1 : 0);
-        int alsaCard = audioDevice.mCard;
-        int alsaDevice = audioDevice.mDevice;
-        if (alsaCard < 0 || alsaDevice < 0) {
-            Slog.e(TAG, "Invalid alsa card or device alsaCard: " + alsaCard +
-                        " alsaDevice: " + alsaDevice);
+        int cardNum = alsaDevice.getCardNum();
+        int deviceNum = alsaDevice.getDeviceNum();
+        if (cardNum < 0 || deviceNum < 0) {
+            Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum
+                        + " alsaDevice: " + deviceNum);
             return;
         }
 
-        String address = AudioService.makeAlsaAddressString(alsaCard, alsaDevice);
+        String address = AudioService.makeAlsaAddressString(cardNum, deviceNum);
         try {
             // Playback Device
-            if (audioDevice.mHasPlayback) {
-                int device;
-                if (mIsOutputHeadset) {
-                    device = AudioSystem.DEVICE_OUT_USB_HEADSET;
-                } else {
-                    device = (audioDevice == mAccessoryAudioDevice
-                        ? AudioSystem.DEVICE_OUT_USB_ACCESSORY
-                        : AudioSystem.DEVICE_OUT_USB_DEVICE);
-                }
+            if (alsaDevice.hasPlayback()) {
+                int device = alsaDevice.isOutputHeadset()
+                        ? AudioSystem.DEVICE_OUT_USB_HEADSET
+                        : AudioSystem.DEVICE_OUT_USB_DEVICE;
                 if (DEBUG) {
                     Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
-                            " addr:" + address + " name:" + audioDevice.getDeviceName());
+                            " addr:" + address + " name:" + alsaDevice.getDeviceName());
                 }
                 mAudioService.setWiredDeviceConnectionState(
-                        device, state, address, audioDevice.getDeviceName(), TAG);
+                        device, state, address, alsaDevice.getDeviceName(), TAG);
             }
 
             // Capture Device
-            if (audioDevice.mHasCapture) {
-                int device;
-                if (mIsInputHeadset) {
-                    device = AudioSystem.DEVICE_IN_USB_HEADSET;
-                } else {
-                    device = (audioDevice == mAccessoryAudioDevice
-                        ? AudioSystem.DEVICE_IN_USB_ACCESSORY
-                        : AudioSystem.DEVICE_IN_USB_DEVICE);
-                }
+            if (alsaDevice.hasCapture()) {
+                int device = alsaDevice.isInputHeadset()
+                        ? AudioSystem.DEVICE_IN_USB_HEADSET
+                        : AudioSystem.DEVICE_IN_USB_DEVICE;
                 mAudioService.setWiredDeviceConnectionState(
-                        device, state, address, audioDevice.getDeviceName(), TAG);
+                        device, state, address, alsaDevice.getDeviceName(), TAG);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
         }
     }
 
-    private AlsaDevice waitForAlsaDevice(int card, int device, int type) {
-        if (DEBUG) {
-            Slog.e(TAG, "waitForAlsaDevice(c:" + card + " d:" + device + ")");
+    private int getAlsaDeviceListIndexFor(String deviceAddress) {
+        for (int index = 0; index < mAlsaDevices.size(); index++) {
+            if (mAlsaDevices.get(index).getDeviceAddress().equals(deviceAddress)) {
+                return index;
+            }
         }
-
-        AlsaDevice testDevice = new AlsaDevice(type, card, device);
-
-        // This value was empirically determined.
-        final int kWaitTimeMs = 2500;
-
-        synchronized(mAlsaDevices) {
-            long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs;
-            do {
-                if (mAlsaDevices.values().contains(testDevice)) {
-                    return testDevice;
-                }
-                long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime();
-                if (waitTimeMs > 0) {
-                    try {
-                        mAlsaDevices.wait(waitTimeMs);
-                    } catch (InterruptedException e) {
-                        Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
-                    }
-                }
-            } while (timeoutMs > SystemClock.elapsedRealtime());
-        }
-
-        Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
-        return null;
+        return -1;
     }
 
-    private void alsaFileAdded(String name) {
-        Slog.i(TAG, "alsaFileAdded(" + name + ")");
-        int type = AlsaDevice.TYPE_UNKNOWN;
-        int card = -1, device = -1;
-
-        if (name.startsWith("pcmC")) {
-            if (name.endsWith("p")) {
-                type = AlsaDevice.TYPE_PLAYBACK;
-            } else if (name.endsWith("c")) {
-                type = AlsaDevice.TYPE_CAPTURE;
-            }
-        } else if (name.startsWith("midiC")) {
-            type = AlsaDevice.TYPE_MIDI;
-        }
-
-        if (type != AlsaDevice.TYPE_UNKNOWN) {
-            try {
-                int c_index = name.indexOf('C');
-                int d_index = name.indexOf('D');
-                int end = name.length();
-                if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {
-                    // skip trailing 'p' or 'c'
-                    end--;
-                }
-                card = Integer.parseInt(name.substring(c_index + 1, d_index));
-                device = Integer.parseInt(name.substring(d_index + 1, end));
-            } catch (Exception e) {
-                Slog.e(TAG, "Could not parse ALSA file name " + name, e);
-                return;
-            }
-            synchronized(mAlsaDevices) {
-                if (mAlsaDevices.get(name) == null) {
-                    AlsaDevice alsaDevice = new AlsaDevice(type, card, device);
-                    Slog.d(TAG, "Adding ALSA device " + alsaDevice);
-                    mAlsaDevices.put(name, alsaDevice);
-                    mAlsaDevices.notifyAll();
-                }
-            }
+    private UsbAlsaDevice removeAlsaDeviceFromList(String deviceAddress) {
+        int index = getAlsaDeviceListIndexFor(deviceAddress);
+        if (index > -1) {
+            return mAlsaDevices.remove(index);
+        } else {
+            return null;
         }
     }
 
-    private void alsaFileRemoved(String path) {
-        synchronized(mAlsaDevices) {
-            AlsaDevice device = mAlsaDevices.remove(path);
-            if (device != null) {
-                Slog.d(TAG, "ALSA device removed: " + device);
-            }
-        }
-    }
-
-    /*
-     * Select the default device of the specified card.
-     */
-    /* package */ UsbAudioDevice selectAudioCard(int card) {
-        if (DEBUG) {
-            Slog.d(TAG, "selectAudioCard() card:" + card
-                    + " isCardUsb(): " + mCardsParser.isCardUsb(card));
-        }
-        if (!mCardsParser.isCardUsb(card)) {
-            // Don't. AudioPolicyManager has logic for falling back to internal devices.
-            return null;
-        }
-
-        if (mDevicesParser.scan() != AlsaDevicesParser.SCANSTATUS_SUCCESS) {
-            Slog.e(TAG, "Error parsing ALSA devices file.");
-            return null;
-        }
-
-        int device = mDevicesParser.getDefaultDeviceNum(card);
-
-        boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card);
-        boolean hasCapture = mDevicesParser.hasCaptureDevices(card);
-        if (DEBUG) {
-            Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
-        }
-
-        int deviceClass =
-            (mCardsParser.isCardUsb(card)
-                ? UsbAudioDevice.kAudioDeviceClass_External
-                : UsbAudioDevice.kAudioDeviceClass_Internal) |
-            UsbAudioDevice.kAudioDeviceMeta_Alsa;
-
-        // Playback device file needed/present?
-        if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
-            return null;
-        }
-
-        // Capture device file needed/present?
-        if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
-            return null;
-        }
-
-        UsbAudioDevice audioDevice =
-                new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
-        AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
-        audioDevice.setDeviceNameAndDescription(cardRecord.mCardName, cardRecord.mCardDescription);
-
-        notifyDeviceState(audioDevice, true /*enabled*/);
-
-        return audioDevice;
-    }
-
-    /* package */ UsbAudioDevice selectDefaultDevice() {
+    /* package */ UsbAlsaDevice selectDefaultDevice() {
         if (DEBUG) {
             Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
         }
-        return selectAudioCard(mCardsParser.getDefaultCard());
+
+        if (mAlsaDevices.size() > 0) {
+            UsbAlsaDevice alsaDevice = mAlsaDevices.get(0);
+            if (DEBUG) {
+                Slog.d(TAG, "  alsaDevice:" + alsaDevice);
+            }
+            if (alsaDevice != null) {
+                notifyDeviceState(alsaDevice, true /*enabled*/);
+            }
+            return alsaDevice;
+        } else {
+            return null;
+        }
     }
 
-    /* package */ void usbDeviceAdded(UsbDevice usbDevice,
-            boolean isInputHeadset, boolean isOutputHeadset) {
+    /* package */ void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
+            UsbDescriptorParser parser) {
         if (DEBUG) {
-            Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName()
+            Slog.d(TAG, "usbDeviceAdded(): " + usbDevice.getManufacturerName()
                     + " nm:" + usbDevice.getProductName());
         }
 
-        mIsInputHeadset = isInputHeadset;
-        mIsOutputHeadset = isOutputHeadset;
+        // Scan the Alsa File Space
+        mCardsParser.scan();
 
-        // Is there an audio interface in there?
-        boolean isAudioDevice = false;
-
-        // FIXME - handle multiple configurations?
-        int interfaceCount = usbDevice.getInterfaceCount();
-        for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < interfaceCount;
-                ntrfaceIndex++) {
-            UsbInterface ntrface = usbDevice.getInterface(ntrfaceIndex);
-            if (ntrface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
-                isAudioDevice = true;
-            }
-        }
-
-        if (DEBUG) {
-            Slog.d(TAG, "  isAudioDevice: " + isAudioDevice);
-        }
-        if (!isAudioDevice) {
+        // Find the ALSA spec for this device address
+        AlsaCardsParser.AlsaCardRecord cardRec =
+                mCardsParser.findCardNumFor(deviceAddress);
+        if (cardRec == null) {
             return;
         }
 
-        int addedCard = mCardsParser.getDefaultUsbCard();
-
-        // If the default isn't a USB device, let the existing "select internal mechanism"
-        // handle the selection.
+        // Add it to the devices list
+        boolean hasInput = parser.hasInput();
+        boolean hasOutput = parser.hasOutput();
         if (DEBUG) {
-            Slog.d(TAG, "  mCardsParser.isCardUsb(" + addedCard + ") = "
-                        + mCardsParser.isCardUsb(addedCard));
+            Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput);
         }
-        if (mCardsParser.isCardUsb(addedCard)) {
-            UsbAudioDevice audioDevice = selectAudioCard(addedCard);
-            if (audioDevice != null) {
-                mAudioDevices.put(usbDevice, audioDevice);
-                Slog.i(TAG, "USB Audio Device Added: " + audioDevice);
+        if (hasInput || hasOutput) {
+            boolean isInputHeadset = parser.isInputHeadset();
+            boolean isOutputHeadset = parser.isOutputHeadset();
+            UsbAlsaDevice alsaDevice =
+                    new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress,
+                            hasOutput, hasInput, isInputHeadset, isOutputHeadset);
+            alsaDevice.setDeviceNameAndDescription(
+                    cardRec.getCardName(), cardRec.getCardDescription());
+            mAlsaDevices.add(0, alsaDevice);
+
+            // Select it
+            if (alsaDevice != null) {
+                notifyDeviceState(alsaDevice, true /*enabled*/);
             }
+        }
 
-            // look for MIDI devices
+        // look for MIDI devices
+        boolean hasMidi = parser.hasMIDIInterface();
+        if (DEBUG) {
+            Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature);
+        }
+        if (hasMidi && mHasMidiFeature) {
+            int device = 0;
+            Bundle properties = new Bundle();
+            String manufacturer = usbDevice.getManufacturerName();
+            String product = usbDevice.getProductName();
+            String version = usbDevice.getVersion();
+            String name;
+            if (manufacturer == null || manufacturer.isEmpty()) {
+                name = product;
+            } else if (product == null || product.isEmpty()) {
+                name = manufacturer;
+            } else {
+                name = manufacturer + " " + product;
+            }
+            properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
+            properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
+            properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+            properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
+            properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+                    usbDevice.getSerialNumber());
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum());
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/);
+            properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
 
-            // Don't need to call mDevicesParser.scan() because selectAudioCard() does this above.
-            // Uncomment this next line if that behavior changes in the fugure.
-            // mDevicesParser.scan()
-
-            boolean hasMidi = mDevicesParser.hasMIDIDevices(addedCard);
-            if (hasMidi && mHasMidiFeature) {
-                int device = mDevicesParser.getDefaultDeviceNum(addedCard);
-                AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
-                if (alsaDevice != null) {
-                    Bundle properties = new Bundle();
-                    String manufacturer = usbDevice.getManufacturerName();
-                    String product = usbDevice.getProductName();
-                    String version = usbDevice.getVersion();
-                    String name;
-                    if (manufacturer == null || manufacturer.isEmpty()) {
-                        name = product;
-                    } else if (product == null || product.isEmpty()) {
-                        name = manufacturer;
-                    } else {
-                        name = manufacturer + " " + product;
-                    }
-                    properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
-                    properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
-                    properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
-                    properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
-                    properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
-                            usbDevice.getSerialNumber());
-                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
-                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
-                    properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
-
-                    UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
-                            alsaDevice.mCard, alsaDevice.mDevice);
-                    if (usbMidiDevice != null) {
-                        mMidiDevices.put(usbDevice, usbMidiDevice);
-                    }
-                }
+            UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
+                    cardRec.getCardNum(), 0 /*device*/);
+            if (usbMidiDevice != null) {
+                mMidiDevices.put(deviceAddress, usbMidiDevice);
             }
         }
 
@@ -455,39 +255,28 @@
         }
     }
 
-    /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
+    /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
         if (DEBUG) {
-          Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
-                  " " + usbDevice.getProductName());
+            Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
         }
 
-        UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
-        Slog.i(TAG, "USB Audio Device Removed: " + audioDevice);
-        if (audioDevice != null) {
-            if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
-                notifyDeviceState(audioDevice, false /*enabled*/);
+        // Audio
+        UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
+        Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
+        if (alsaDevice != null) {
+            if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) {
+                notifyDeviceState(alsaDevice, false /*enabled*/);
 
                 // if there any external devices left, select one of them
                 selectDefaultDevice();
             }
         }
-        UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
-        if (usbMidiDevice != null) {
-            IoUtils.closeQuietly(usbMidiDevice);
-        }
-    }
 
-   /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
-       if (DEBUG) {
-            Slog.d(TAG, "setAccessoryAudioState " + enabled + " " + card + " " + device);
-        }
-        if (enabled) {
-            mAccessoryAudioDevice = new UsbAudioDevice(card, device, true, false,
-                    UsbAudioDevice.kAudioDeviceClass_External);
-            notifyDeviceState(mAccessoryAudioDevice, true /*enabled*/);
-        } else if (mAccessoryAudioDevice != null) {
-            notifyDeviceState(mAccessoryAudioDevice, false /*enabled*/);
-            mAccessoryAudioDevice = null;
+        // MIDI
+        UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress);
+        if (usbMidiDevice != null) {
+            Slog.i(TAG, "USB MIDI Device Removed: " + usbMidiDevice);
+            IoUtils.closeQuietly(usbMidiDevice);
         }
     }
 
@@ -515,44 +304,31 @@
    }
 
     //
-    // Devices List
-    //
-/*
-    //import java.util.ArrayList;
-    public ArrayList<UsbAudioDevice> getConnectedDevices() {
-        ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
-        for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
-            devices.add(entry.getValue());
-        }
-        return devices;
-    }
-*/
-
-    //
     // Logging
     //
     // called by UsbService.dump
     public void dump(IndentingPrintWriter pw) {
         pw.println("Parsers Scan Status:");
         pw.println("  Cards Parser: " + mCardsParser.getScanStatus());
-        pw.println("  Devices Parser: " + mDevicesParser.getScanStatus());
+//        pw.println("  Devices Parser: " + mDevicesParser.getScanStatus());
         pw.println("USB Audio Devices:");
-        for (UsbDevice device : mAudioDevices.keySet()) {
-            pw.println("  " + device.getDeviceName() + ": " + mAudioDevices.get(device));
+        for (UsbAlsaDevice usbAlsaDevice : mAlsaDevices) {
+            pw.println("  " + usbAlsaDevice.getDeviceAddress() + ": " + usbAlsaDevice);
         }
         pw.println("USB MIDI Devices:");
-        for (UsbDevice device : mMidiDevices.keySet()) {
-            pw.println("  " + device.getDeviceName() + ": " + mMidiDevices.get(device));
+        for (String deviceAddr : mMidiDevices.keySet()) {
+            UsbMidiDevice midiDevice = mMidiDevices.get(deviceAddr);
+            pw.println("  " + deviceAddr + ": " + midiDevice);
         }
     }
 
 /*
     public void logDevicesList(String title) {
       if (DEBUG) {
-          for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+          for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) {
               Slog.i(TAG, "UsbDevice-------------------");
               Slog.i(TAG, "" + (entry != null ? entry.getKey() : "[none]"));
-              Slog.i(TAG, "UsbAudioDevice--------------");
+              Slog.i(TAG, "UsbAlsaDevice--------------");
               Slog.i(TAG, "" + entry.getValue());
           }
       }
@@ -564,7 +340,7 @@
     public void logDevices(String title) {
       if (DEBUG) {
           Slog.i(TAG, title);
-          for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+          for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) {
               Slog.i(TAG, entry.getValue().toShortString());
           }
       }
diff --git a/services/usb/java/com/android/server/usb/UsbAudioDevice.java b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
deleted file mode 100644
index 4b17dfe..0000000
--- a/services/usb/java/com/android/server/usb/UsbAudioDevice.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2014 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 an
- * limitations under the License.
- */
-
-package com.android.server.usb;
-
-public final class UsbAudioDevice {
-    private static final String TAG = "UsbAudioDevice";
-    protected static final boolean DEBUG = false;
-
-    public final int mCard;
-    public final int mDevice;
-    public final boolean mHasPlayback;
-    public final boolean mHasCapture;
-
-    // Device "class" flags
-    public static final int kAudioDeviceClassMask = 0x00FFFFFF;
-    public static final int kAudioDeviceClass_Undefined = 0x00000000;
-    public static final int kAudioDeviceClass_Internal = 0x00000001;
-    public static final int kAudioDeviceClass_External = 0x00000002;
-    // Device meta-data flags
-    public static final int kAudioDeviceMetaMask = 0xFF000000;
-    public static final int kAudioDeviceMeta_Alsa = 0x80000000;
-    // This member is a combination of the above bit-flags
-    public final int mDeviceClass;
-
-    private String mDeviceName = "";
-    private String mDeviceDescription = "";
-
-    public UsbAudioDevice(int card, int device,
-            boolean hasPlayback, boolean hasCapture, int deviceClass) {
-        mCard = card;
-        mDevice = device;
-        mHasPlayback = hasPlayback;
-        mHasCapture = hasCapture;
-        mDeviceClass = deviceClass;
-    }
-
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("UsbAudioDevice: [card: " + mCard);
-        sb.append(", device: " + mDevice);
-        sb.append(", name: " + mDeviceName);
-        sb.append(", hasPlayback: " + mHasPlayback);
-        sb.append(", hasCapture: " + mHasCapture);
-        sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]");
-        return sb.toString();
-    }
-
-    // called by logDevices
-    String toShortString() {
-        return "[card:" + mCard + " device:" + mDevice + " " + mDeviceName + "]";
-    }
-
-    String getDeviceName() {
-        return mDeviceName;
-    }
-
-    void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
-        mDeviceName = deviceName;
-        mDeviceDescription = deviceDescription;
-    }
-
-}
-
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 55ffea6..a67e7f3 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -726,35 +726,9 @@
         }
 
         private void updateUsbFunctions() {
-            updateAudioSourceFunction();
             updateMidiFunction();
         }
 
-        private void updateAudioSourceFunction() {
-            boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_AUDIO_SOURCE) != 0;
-            if (enabled != mAudioSourceEnabled) {
-                int card = -1;
-                int device = -1;
-
-                if (enabled) {
-                    Scanner scanner = null;
-                    try {
-                        scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
-                        card = scanner.nextInt();
-                        device = scanner.nextInt();
-                    } catch (FileNotFoundException e) {
-                        Slog.e(TAG, "could not open audio source PCM file", e);
-                    } finally {
-                        if (scanner != null) {
-                            scanner.close();
-                        }
-                    }
-                }
-                mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
-                mAudioSourceEnabled = enabled;
-            }
-        }
-
         private void updateMidiFunction() {
             boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_MIDI) != 0;
             if (enabled != mMidiEnabled) {
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7a352a4..58f91477 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -44,7 +44,7 @@
  */
 public class UsbHostManager {
     private static final String TAG = UsbHostManager.class.getSimpleName();
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
 
@@ -230,6 +230,7 @@
     }
 
     private boolean isBlackListed(String deviceAddress) {
+        Slog.i(TAG, "isBlackListed(" + deviceAddress + ")");
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
             if (deviceAddress.startsWith(mHostBlacklist[i])) {
@@ -241,6 +242,7 @@
 
     /* returns true if the USB device should not be accessible by applications */
     private boolean isBlackListed(int clazz, int subClass) {
+        Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")");
         // blacklist hubs
         if (clazz == UsbConstants.USB_CLASS_HUB) return true;
 
@@ -312,13 +314,7 @@
                                 usbDeviceConnectionHandler);
                     }
 
-                    // Headset?
-                    boolean isInputHeadset = parser.isInputHeadset();
-                    boolean isOutputHeadset = parser.isOutputHeadset();
-                    Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
-                            + " , out: " + isOutputHeadset + "]");
-
-                    mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
+                    mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
 
                     // Tracking
                     addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
@@ -343,10 +339,13 @@
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     @SuppressWarnings("unused")
     private void usbDeviceRemoved(String deviceAddress) {
+        if (DEBUG) {
+            Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start");
+        }
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceAddress);
             if (device != null) {
-                mUsbAlsaManager.usbDeviceRemoved(device);
+                mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
                 mSettingsManager.usbDeviceRemoved(device);
                 getCurrentUserSettings().usbDeviceRemoved(device);
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 7a1e9e2..297a6ea 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -26,7 +26,7 @@
  */
 public final class UsbDescriptorParser {
     private static final String TAG = "UsbDescriptorParser";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private final String mDeviceAddr;
 
@@ -358,6 +358,139 @@
         return list;
     }
 
+    /*
+     * Attribute predicates
+     */
+    /**
+     * @hide
+     */
+    public boolean hasInput() {
+        if (DEBUG) {
+            Log.d(TAG, "---- hasInput()");
+        }
+        ArrayList<UsbDescriptor> acDescriptors =
+                getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+                UsbACInterface.AUDIO_AUDIOCONTROL);
+        boolean hasInput = false;
+        for (UsbDescriptor descriptor : acDescriptors) {
+            if (descriptor instanceof UsbACTerminal) {
+                UsbACTerminal inDescr = (UsbACTerminal) descriptor;
+                // Check for input and bi-directional terminal types
+                int type = inDescr.getTerminalType();
+                if (DEBUG) {
+                    Log.d(TAG, "  type:0x" + Integer.toHexString(type));
+                }
+                if ((type >= UsbTerminalTypes.TERMINAL_IN_UNDEFINED
+                            && type <= UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY)
+                        || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+                            && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)
+                        || (type == UsbTerminalTypes.TERMINAL_USB_STREAMING)) {
+                    hasInput = true;
+                    break;
+                }
+            } else {
+                Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+                        + " t:0x" + Integer.toHexString(descriptor.getType()));
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "hasInput() = " + hasInput);
+        }
+        return hasInput;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasOutput() {
+        if (DEBUG) {
+            Log.d(TAG, "---- hasOutput()");
+        }
+        ArrayList<UsbDescriptor> acDescriptors =
+                getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+                UsbACInterface.AUDIO_AUDIOCONTROL);
+        boolean hasOutput = false;
+        for (UsbDescriptor descriptor : acDescriptors) {
+            if (descriptor instanceof UsbACTerminal) {
+                UsbACTerminal outDescr = (UsbACTerminal) descriptor;
+                // Check for output and bi-directional terminal types
+                int type = outDescr.getTerminalType();
+                if (DEBUG) {
+                    Log.d(TAG, "  type:0x" + Integer.toHexString(type));
+                }
+                if ((type >= UsbTerminalTypes.TERMINAL_OUT_UNDEFINED
+                            && type <= UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER)
+                        || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+                            && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)) {
+                    hasOutput = true;
+                    break;
+                }
+            } else {
+                Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+                        + " t:0x" + Integer.toHexString(descriptor.getType()));
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG, "hasOutput() = " + hasOutput);
+        }
+        return hasOutput;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasMic() {
+        boolean hasMic = false;
+
+        ArrayList<UsbDescriptor> acDescriptors =
+                getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+                UsbACInterface.AUDIO_AUDIOCONTROL);
+        for (UsbDescriptor descriptor : acDescriptors) {
+            if (descriptor instanceof UsbACTerminal) {
+                UsbACTerminal inDescr = (UsbACTerminal) descriptor;
+                if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
+                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
+                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
+                    hasMic = true;
+                    break;
+                }
+            } else {
+                Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+                        + " t:0x" + Integer.toHexString(descriptor.getType()));
+            }
+        }
+        return hasMic;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasSpeaker() {
+        boolean hasSpeaker = false;
+
+        ArrayList<UsbDescriptor> acDescriptors =
+                getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+                        UsbACInterface.AUDIO_AUDIOCONTROL);
+        for (UsbDescriptor descriptor : acDescriptors) {
+            if (descriptor instanceof UsbACTerminal) {
+                UsbACTerminal outDescr = (UsbACTerminal) descriptor;
+                if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
+                        || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
+                        || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
+                    hasSpeaker = true;
+                    break;
+                }
+            } else {
+                Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
+                        + " t:0x" + Integer.toHexString(descriptor.getType()));
+            }
+        }
+
+        return hasSpeaker;
+    }
+
     /**
      * @hide
      */
@@ -397,48 +530,12 @@
         }
 
         float probability = 0.0f;
-        ArrayList<UsbDescriptor> acDescriptors;
 
         // Look for a microphone
-        boolean hasMic = false;
-        acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
-                UsbACInterface.AUDIO_AUDIOCONTROL);
-        for (UsbDescriptor descriptor : acDescriptors) {
-            if (descriptor instanceof UsbACTerminal) {
-                UsbACTerminal inDescr = (UsbACTerminal) descriptor;
-                if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
-                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
-                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
-                        || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
-                    hasMic = true;
-                    break;
-                }
-            } else {
-                Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
-                        + " t:0x" + Integer.toHexString(descriptor.getType()));
-            }
-        }
+        boolean hasMic = hasMic();
 
         // Look for a "speaker"
-        boolean hasSpeaker = false;
-        acDescriptors =
-                getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
-                        UsbACInterface.AUDIO_AUDIOCONTROL);
-        for (UsbDescriptor descriptor : acDescriptors) {
-            if (descriptor instanceof UsbACTerminal) {
-                UsbACTerminal outDescr = (UsbACTerminal) descriptor;
-                if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
-                        || outDescr.getTerminalType()
-                            == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
-                        || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
-                    hasSpeaker = true;
-                    break;
-                }
-            } else {
-                Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
-                        + " t:0x" + Integer.toHexString(descriptor.getType()));
-            }
-        }
+        boolean hasSpeaker = hasSpeaker();
 
         if (hasMic && hasSpeaker) {
             probability += 0.75f;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index fcfc593..95eb14a 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -134,6 +134,25 @@
             "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
 
     /**
+     * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
+     * indicates whether calls for a {@link PhoneAccount} should generate a "call recording tone"
+     * when the user is recording audio on the device.
+     * <p>
+     * The call recording tone is played over the telephony audio stream so that the remote party
+     * has an audible indication that it is possible their call is being recorded using a call
+     * recording app on the device.
+     * <p>
+     * This extra only has an effect for calls placed via Telephony (e.g.
+     * {@link #CAPABILITY_SIM_SUBSCRIPTION}).
+     * <p>
+     * The call recording tone is a 1400 hz tone which repeats every 15 seconds while recording is
+     * in progress.
+     * @hide
+     */
+    public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
+            "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
+
+    /**
      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
      * will be allowed to manage phone calls including using its own proprietary phone-call
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a34e9f9..63ab766 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -77,6 +77,14 @@
     public static final String
             KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
 
+   /**
+    * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
+    * true means visible. false means gone.
+    * @hide
+    */
+    public static final String KEY_CALL_BARRING_VISIBILITY_BOOL =
+            "call_barring_visibility_bool";
+
     /**
      * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
      * events from the Sim.
@@ -146,6 +154,15 @@
     public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
 
     /**
+     * Determines if the carrier requires that a tone be played to the remote party when an app is
+     * recording audio during a call (e.g. using a call recording app).
+     * <p>
+     * Note: This requires the Telephony config_supports_telephony_audio_device overlay to be true
+     * in order to work.
+     * @hide
+     */
+    public static final String KEY_PLAY_CALL_RECORDING_TONE_BOOL = "play_call_recording_tone_bool";
+    /**
      * Determines if the carrier requires converting the destination number before sending out an
      * SMS. Certain networks and numbering plans require different formats.
      */
@@ -1381,6 +1398,14 @@
     public static final String KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO = "video_calls_can_be_hd_audio";
 
     /**
+     * When true, indicates that the HD audio icon in the in-call screen should be shown for
+     * GSM/CDMA calls.
+     * @hide
+     */
+    public static final String KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO =
+            "gsm_cdma_calls_can_be_hd_audio";
+
+    /**
      * Whether system apps are allowed to use fallback if carrier video call is not available.
      * Defaults to {@code true}.
      *
@@ -1793,6 +1818,7 @@
         sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_LOCAL_DTMF_TONES_BOOL, true);
+        sDefaults.putBoolean(KEY_PLAY_CALL_RECORDING_TONE_BOOL, false);
         sDefaults.putBoolean(KEY_APN_EXPAND_BOOL, true);
         sDefaults.putBoolean(KEY_AUTO_RETRY_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
@@ -1833,6 +1859,7 @@
         sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
 
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
+        sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
@@ -2033,6 +2060,7 @@
         sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true);
         sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true);
+        sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false);
         sDefaults.putBoolean(KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL, true);
 
         sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index dfaaab9..ece1ee3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -36,48 +36,14 @@
     private int mEvdoEcio;  // This value is the EVDO Ec/Io
     private int mEvdoSnr;   // Valid values are 0-8.  8 is the highest signal to noise ratio
 
-    /**
-     * Empty constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthCdma() {
         setDefaultValues();
     }
 
-    /**
-     * Constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio,
             int evdoSnr) {
-        initialize(cdmaDbm, cdmaEcio, evdoDbm, evdoEcio, evdoSnr);
-    }
-
-    /**
-     * Copy constructors
-     *
-     * @param s Source SignalStrength
-     *
-     * @hide
-     */
-    public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
-        copyFrom(s);
-    }
-
-    /**
-     * Initialize all the values
-     *
-     * @param cdmaDbm
-     * @param cdmaEcio
-     * @param evdoDbm
-     * @param evdoEcio
-     * @param evdoSnr
-     *
-     * @hide
-     */
-    public void initialize(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, int evdoSnr) {
         mCdmaDbm = cdmaDbm;
         mCdmaEcio = cdmaEcio;
         mEvdoDbm = evdoDbm;
@@ -85,9 +51,12 @@
         mEvdoSnr = evdoSnr;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
+    public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
+        copyFrom(s);
+    }
+
+    /** @hide */
     protected void copyFrom(CellSignalStrengthCdma s) {
         mCdmaDbm = s.mCdmaDbm;
         mCdmaEcio = s.mCdmaEcio;
@@ -96,9 +65,7 @@
         mEvdoSnr = s.mEvdoSnr;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
     public CellSignalStrengthCdma copy() {
         return new CellSignalStrengthCdma(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index f68d2ca..8687cd1 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -34,80 +34,40 @@
     private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
     private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
 
-    private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
+    private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
-    private int mTimingAdvance;
+    private int mTimingAdvance; // range from 0-219 or Integer.MAX_VALUE if unknown
 
-    /**
-     * Empty constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthGsm() {
         setDefaultValues();
     }
 
-    /**
-     * Constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthGsm(int ss, int ber) {
-        initialize(ss, ber);
+        this(ss, ber, Integer.MAX_VALUE);
     }
 
-    /**
-     * Copy constructors
-     *
-     * @param s Source SignalStrength
-     *
-     * @hide
-     */
-    public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
-        copyFrom(s);
-    }
-
-    /**
-     * Initialize all the values
-     *
-     * @param ss SignalStrength as ASU value
-     * @param ber is Bit Error Rate
-     *
-     * @hide
-     */
-    public void initialize(int ss, int ber) {
-        mSignalStrength = ss;
-        mBitErrorRate = ber;
-        mTimingAdvance = Integer.MAX_VALUE;
-    }
-
-    /**
-     * Initialize all the values
-     *
-     * @param ss SignalStrength as ASU value
-     * @param ber is Bit Error Rate
-     * @param ta timing advance
-     *
-     * @hide
-     */
-    public void initialize(int ss, int ber, int ta) {
+    /** @hide */
+    public CellSignalStrengthGsm(int ss, int ber, int ta) {
         mSignalStrength = ss;
         mBitErrorRate = ber;
         mTimingAdvance = ta;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
+    public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
+        copyFrom(s);
+    }
+
+    /** @hide */
     protected void copyFrom(CellSignalStrengthGsm s) {
         mSignalStrength = s.mSignalStrength;
         mBitErrorRate = s.mBitErrorRate;
         mTimingAdvance = s.mTimingAdvance;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
     public CellSignalStrengthGsm copy() {
         return new CellSignalStrengthGsm(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 6ffc8b6..f009fb1 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -37,50 +37,15 @@
     private int mCqi;
     private int mTimingAdvance;
 
-    /**
-     * Empty constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthLte() {
         setDefaultValues();
     }
 
-    /**
-     * Constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthLte(int signalStrength, int rsrp, int rsrq, int rssnr, int cqi,
             int timingAdvance) {
-        initialize(signalStrength, rsrp, rsrq, rssnr, cqi, timingAdvance);
-    }
-
-    /**
-     * Copy constructors
-     *
-     * @param s Source SignalStrength
-     *
-     * @hide
-     */
-    public CellSignalStrengthLte(CellSignalStrengthLte s) {
-        copyFrom(s);
-    }
-
-    /**
-     * Initialize all the values
-     *
-     * @param lteSignalStrength
-     * @param rsrp
-     * @param rsrq
-     * @param rssnr
-     * @param cqi
-     *
-     * @hide
-     */
-    public void initialize(int lteSignalStrength, int rsrp, int rsrq, int rssnr, int cqi,
-            int timingAdvance) {
-        mSignalStrength = lteSignalStrength;
+        mSignalStrength = signalStrength;
         mRsrp = rsrp;
         mRsrq = rsrq;
         mRssnr = rssnr;
@@ -88,25 +53,12 @@
         mTimingAdvance = timingAdvance;
     }
 
-    /**
-     * Initialize from the SignalStrength structure.
-     *
-     * @param ss
-     *
-     * @hide
-     */
-    public void initialize(SignalStrength ss, int timingAdvance) {
-        mSignalStrength = ss.getLteSignalStrength();
-        mRsrp = ss.getLteRsrp();
-        mRsrq = ss.getLteRsrq();
-        mRssnr = ss.getLteRssnr();
-        mCqi = ss.getLteCqi();
-        mTimingAdvance = timingAdvance;
+    /** @hide */
+    public CellSignalStrengthLte(CellSignalStrengthLte s) {
+        copyFrom(s);
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     protected void copyFrom(CellSignalStrengthLte s) {
         mSignalStrength = s.mSignalStrength;
         mRsrp = s.mRsrp;
@@ -116,9 +68,7 @@
         mTimingAdvance = s.mTimingAdvance;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
     public CellSignalStrengthLte copy() {
         return new CellSignalStrengthLte(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 2cd56b8..dd32a96 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -34,62 +34,32 @@
     private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
     private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
 
-    private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
-    private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+    private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
+    private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
 
-    /**
-     * Empty constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthWcdma() {
         setDefaultValues();
     }
 
-    /**
-     * Constructor
-     *
-     * @hide
-     */
+    /** @hide */
     public CellSignalStrengthWcdma(int ss, int ber) {
-        initialize(ss, ber);
-    }
-
-    /**
-     * Copy constructors
-     *
-     * @param s Source SignalStrength
-     *
-     * @hide
-     */
-    public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
-        copyFrom(s);
-    }
-
-    /**
-     * Initialize all the values
-     *
-     * @param ss SignalStrength as ASU value
-     * @param ber is Bit Error Rate
-     *
-     * @hide
-     */
-    public void initialize(int ss, int ber) {
         mSignalStrength = ss;
         mBitErrorRate = ber;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
+    public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
+        copyFrom(s);
+    }
+
+    /** @hide */
     protected void copyFrom(CellSignalStrengthWcdma s) {
         mSignalStrength = s.mSignalStrength;
         mBitErrorRate = s.mBitErrorRate;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
     public CellSignalStrengthWcdma copy() {
         return new CellSignalStrengthWcdma(this);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
new file mode 100644
index 0000000..b362df9
--- /dev/null
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.SparseBooleanArray;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper for performing location access checks.
+ * @hide
+ */
+public final class LocationAccessPolicy {
+    /**
+     * API to determine if the caller has permissions to get cell location.
+     *
+     * @param pkgName Package name of the application requesting access
+     * @param uid The uid of the package
+     * @param pid The pid of the package
+     * @return boolean true or false if permissions is granted
+     */
+    public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
+            int uid, int pid) throws SecurityException {
+        Trace.beginSection("TelephonyLocationCheck");
+        try {
+            // Always allow the phone process to access location. This avoid breaking legacy code
+            // that rely on public-facing APIs to access cell location, and it doesn't create a
+            // info leak risk because the cell location is stored in the phone process anyway.
+            if (uid == Process.PHONE_UID) {
+                return true;
+            }
+
+            // We always require the location permission and also require the
+            // location mode to be on for non-legacy apps. Legacy apps are
+            // required to be in the foreground to at least mitigate the case
+            // where a legacy app the user is not using tracks their location.
+            // Granting ACCESS_FINE_LOCATION to an app automatically grants it
+            // ACCESS_COARSE_LOCATION.
+
+            if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
+                    PackageManager.PERMISSION_DENIED) {
+                return false;
+            }
+            final int opCode = AppOpsManager.permissionToOpCode(
+                    Manifest.permission.ACCESS_COARSE_LOCATION);
+            if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
+                    .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+            if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
+                    && !isLegacyForeground(context, pkgName, uid)) {
+                return false;
+            }
+            // If the user or profile is current, permission is granted.
+            // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
+            return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+        int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
+        return locationMode != Settings.Secure.LOCATION_MODE_OFF
+                && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
+    }
+
+    private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
+            int uid) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
+        try {
+            if (context.getPackageManager().getApplicationInfo(pkgName, 0)
+                    .targetSdkVersion <= Build.VERSION_CODES.O) {
+                return true;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // In case of exception, assume known app (more strict checking)
+            // Note: This case will never happen since checkPackage is
+            // called to verify validity before checking app's version.
+        }
+        return false;
+    }
+
+    private static boolean isForegroundApp(@NonNull Context context, int uid) {
+        final ActivityManager am = context.getSystemService(ActivityManager.class);
+        return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+    }
+
+    private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
+        return context.checkCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private static boolean isCurrentProfile(@NonNull Context context, int uid) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            final int currentUser = ActivityManager.getCurrentUser();
+            final int callingUserId = UserHandle.getUserId(uid);
+            if (callingUserId == currentUser) {
+                return true;
+            } else {
+                List<UserInfo> userProfiles = context.getSystemService(
+                        UserManager.class).getProfiles(currentUser);
+                for (UserInfo user : userProfiles) {
+                    if (user.id == callingUserId) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index debf43d..34f2dac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -612,9 +612,9 @@
      *                 onSubscriptionsChanged overridden.
      */
     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
-        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (DBG) {
-            logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
+            logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
                     + " listener=" + listener);
         }
         try {
@@ -623,7 +623,7 @@
             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                     "telephony.registry"));
             if (tr != null) {
-                tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
+                tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
             }
         } catch (RemoteException ex) {
             // Should not happen
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
index 7145110..021e386 100644
--- a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -14,12 +14,16 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.frameworks.perftests.amteststestapp">
+        package="com.android.frameworks.perftests.amteststestapp">
     <application android:name=".TestApplication">
         <activity android:name=".TestActivity" android:exported="true"/>
+        <provider
+                android:authorities="com.android.frameworks.perftests.amteststestapp"
+                android:name=".TestContentProvider"
+                android:exported="true" />
         <receiver
-            android:name=".TestBroadcastReceiver"
-            android:exported="true">
+                android:name=".TestBroadcastReceiver"
+                android:exported="true">
             <intent-filter>
                 <action android:name="com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java
new file mode 100644
index 0000000..0940578
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.frameworks.perftests.amteststestapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestContentProvider extends ContentProvider {
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return false;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java
new file mode 100644
index 0000000..3bf56ce
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.frameworks.perftests.am.tests;
+
+import android.content.ContentProviderClient;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ContentProviderPerfTest extends BasePerfTest {
+    /**
+     * Benchmark time to call ContentResolver.acquireContentProviderClient() when target package is
+     * running.
+     */
+    @Test
+    public void contentProviderRunning() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            long startTimeNs = System.nanoTime();
+            final ContentProviderClient contentProviderClient =
+                    mContext.getContentResolver()
+                            .acquireContentProviderClient(TargetPackageUtils.PACKAGE_NAME);
+            final long endTimeNs = System.nanoTime();
+
+            contentProviderClient.close();
+
+            return endTimeNs - startTimeNs;
+        });
+    }
+
+    /**
+     * Benchmark time to call ContentResolver.acquireContentProviderClient() when target package is
+     * not running.
+     */
+    @Test
+    public void contentProviderNotRunning() {
+        runPerfFunction(() -> {
+            final long startTimeNs = System.nanoTime();
+            final ContentProviderClient contentProviderClient =
+                    mContext.getContentResolver().acquireContentProviderClient(
+                            TargetPackageUtils.PACKAGE_NAME);
+            final long endTimeNs = System.nanoTime();
+
+            contentProviderClient.close();
+
+            return endTimeNs - startTimeNs;
+        });
+    }
+}
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 1443fc1..063060f 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -83,7 +83,7 @@
     private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
     private static final String WEARABLE_ACTION_GOOGLE =
             "com.google.android.wearable.action.GOOGLE";
-    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
+    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle
     private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
     private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
     private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";