Merge "Add sungsoo@ to OWNERS"
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index 75cb229..b7b87dd 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -22,6 +22,8 @@
 # Use google-fonts/dancing-script for the performance metrics
 LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script
 
+LOCAL_COMPATIBILITY_SUITE += device-tests
+
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/cmds/webview_zygote/Android.mk b/cmds/webview_zygote/Android.mk
deleted file mode 100644
index 955e58e..0000000
--- a/cmds/webview_zygote/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := webview_zygote
-
-LOCAL_SRC_FILES := webview_zygote.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	libandroid_runtime \
-	libbinder \
-	liblog \
-	libcutils \
-	libutils
-
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-
-LOCAL_INIT_RC := webview_zygote32.rc
-
-# Always include the 32-bit version of webview_zygote. If the target is 64-bit,
-# also include the 64-bit webview_zygote.
-ifeq ($(TARGET_SUPPORTS_64_BIT_APPS),true)
-	LOCAL_INIT_RC += webview_zygote64.rc
-endif
-
-LOCAL_MULTILIB := both
-
-LOCAL_MODULE_STEM_32 := webview_zygote32
-LOCAL_MODULE_STEM_64 := webview_zygote64
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/webview_zygote/webview_zygote.cpp b/cmds/webview_zygote/webview_zygote.cpp
deleted file mode 100644
index 88fee64..0000000
--- a/cmds/webview_zygote/webview_zygote.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#define LOG_TAG "WebViewZygote"
-
-#include <sys/prctl.h>
-
-#include <android_runtime/AndroidRuntime.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-class WebViewRuntime : public AndroidRuntime {
-public:
-    WebViewRuntime(char* argBlockStart, size_t argBlockSize)
-        : AndroidRuntime(argBlockStart, argBlockSize) {}
-
-    ~WebViewRuntime() override {}
-
-    void onStarted() override {
-        // Nothing to do since this is a zygote server.
-    }
-
-    void onVmCreated(JNIEnv*) override {
-        // Nothing to do when the VM is created in the zygote.
-    }
-
-    void onZygoteInit() override {
-        // Called after a new process is forked.
-        sp<ProcessState> proc = ProcessState::self();
-        proc->startThreadPool();
-    }
-
-    void onExit(int code) override {
-        IPCThreadState::self()->stopProcess();
-        AndroidRuntime::onExit(code);
-    }
-};
-
-}  // namespace android
-
-int main(int argc, char* const argv[]) {
-    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
-        LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
-        return 12;
-    }
-
-    size_t argBlockSize = 0;
-    for (int i = 0; i < argc; ++i) {
-        argBlockSize += strlen(argv[i]) + 1;
-    }
-
-    android::WebViewRuntime runtime(argv[0], argBlockSize);
-    runtime.addOption("-Xzygote");
-
-    android::Vector<android::String8> args;
-    runtime.start("com.android.internal.os.WebViewZygoteInit", args, /*zygote=*/ true);
-}
diff --git a/cmds/webview_zygote/webview_zygote32.rc b/cmds/webview_zygote/webview_zygote32.rc
deleted file mode 100644
index b7decc8..0000000
--- a/cmds/webview_zygote/webview_zygote32.rc
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-service webview_zygote32 /system/bin/webview_zygote32
-    user webview_zygote
-    socket webview_zygote stream 660 webview_zygote system
-
-on property:init.svc.zygote=stopped
-    stop webview_zygote32
diff --git a/cmds/webview_zygote/webview_zygote64.rc b/cmds/webview_zygote/webview_zygote64.rc
deleted file mode 100644
index 2935b28..0000000
--- a/cmds/webview_zygote/webview_zygote64.rc
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-service webview_zygote64 /system/bin/webview_zygote64
-    user webview_zygote
-    socket webview_zygote stream 660 webview_zygote system
-
-on property:init.svc.zygote=stopped
-    stop webview_zygote64
diff --git a/core/java/android/hardware/radio/OWNERS b/core/java/android/hardware/radio/OWNERS
new file mode 100644
index 0000000..ea4421e
--- /dev/null
+++ b/core/java/android/hardware/radio/OWNERS
@@ -0,0 +1,2 @@
+twasilczyk@google.com
+randolphs@google.com
diff --git a/core/java/android/util/RecurrenceRule.java b/core/java/android/util/RecurrenceRule.java
index 1fe638d..cd8b097 100644
--- a/core/java/android/util/RecurrenceRule.java
+++ b/core/java/android/util/RecurrenceRule.java
@@ -41,7 +41,7 @@
  */
 public class RecurrenceRule implements Parcelable {
     private static final String TAG = "RecurrenceRule";
-    private static final boolean DEBUG = true;
+    private static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int VERSION_INIT = 0;
 
@@ -192,7 +192,7 @@
         public RecurringIterator() {
             final ZonedDateTime anchor = (end != null) ? end
                     : ZonedDateTime.now(sClock).withZoneSameInstant(start.getZone());
-            if (DEBUG) Log.d(TAG, "Resolving using anchor " + anchor);
+            if (LOGD) Log.d(TAG, "Resolving using anchor " + anchor);
 
             updateCycle();
 
@@ -231,7 +231,7 @@
 
         @Override
         public Pair<ZonedDateTime, ZonedDateTime> next() {
-            if (DEBUG) Log.d(TAG, "Cycle " + i + " from " + cycleStart + " to " + cycleEnd);
+            if (LOGD) Log.d(TAG, "Cycle " + i + " from " + cycleStart + " to " + cycleEnd);
             Pair<ZonedDateTime, ZonedDateTime> p = new Pair<>(cycleStart, cycleEnd);
             i--;
             updateCycle();
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 4146f6f..40db758 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -373,9 +373,9 @@
     static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
     static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
     static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
-    static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0401;
-    static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0403;
-    static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0405;
+    static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0411;
+    static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0413;
+    static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0415;
 
     static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
     static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -754,9 +754,6 @@
                 md.update(buffer);
             }
         }
-
-        @Override
-        public void finish() {}
     }
 
 }
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index a3eeb27..7b89967 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -207,14 +207,10 @@
             }
         }
 
-        /** Finish the current digestion if any. */
-        @Override
-        public void finish() throws DigestException {
-            if (mBytesDigestedSinceReset == 0) {
-                return;
+        public void assertEmptyBuffer() throws DigestException {
+            if (mBytesDigestedSinceReset != 0) {
+                throw new IllegalStateException("Buffer is not empty: " + mBytesDigestedSinceReset);
             }
-            mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
-            mOutput.put(mDigestBuffer);
         }
 
         private void fillUpLastOutputChunk() {
@@ -279,9 +275,15 @@
                 new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
                     apk.length() - offsetAfterEocdCdOffsetField),
                 MMAP_REGION_SIZE_BYTES);
-        digester.finish();
 
-        // 5. Fill up the rest of buffer with 0s.
+        // 5. Pad 0s up to the nearest 4096-byte block before hashing.
+        int lastIncompleteChunkSize = (int) (apk.length() % CHUNK_SIZE_BYTES);
+        if (lastIncompleteChunkSize != 0) {
+            digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
+        }
+        digester.assertEmptyBuffer();
+
+        // 6. Fill up the rest of buffer with 0s.
         digester.fillUpLastOutputChunk();
     }
 
@@ -300,8 +302,7 @@
             DataSource source = new ByteBufferDataSource(inputBuffer);
             BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
             consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
-            digester.finish();
-
+            digester.assertEmptyBuffer();
             digester.fillUpLastOutputChunk();
         }
 
@@ -309,7 +310,7 @@
         byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
         BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
         digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
-        digester.finish();
+        digester.assertEmptyBuffer();
         return rootHash;
     }
 
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
index 278be80..18d1dff 100644
--- a/core/java/android/util/apk/DataDigester.java
+++ b/core/java/android/util/apk/DataDigester.java
@@ -22,7 +22,4 @@
 interface DataDigester {
     /** Consumes the {@link ByteBuffer}. */
     void consume(ByteBuffer buffer) throws DigestException;
-
-    /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
-    void finish() throws DigestException;
 }
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index db60ad8..63fbef3 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -20,28 +20,22 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build;
-import android.os.SystemService;
+import android.os.ChildZygoteProcess;
+import android.os.Process;
 import android.os.ZygoteProcess;
 import android.text.TextUtils;
-import android.util.AndroidRuntimeException;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-import java.util.concurrent.TimeoutException;
 
 /** @hide */
 public class WebViewZygote {
     private static final String LOGTAG = "WebViewZygote";
 
-    private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
-    private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
-    private static final String WEBVIEW_ZYGOTE_SOCKET = "webview_zygote";
-
     /**
      * Lock object that protects all other static members.
      */
@@ -52,14 +46,7 @@
      * zygote is not running or is not connected.
      */
     @GuardedBy("sLock")
-    private static ZygoteProcess sZygote;
-
-    /**
-     * Variable that allows us to determine whether the WebView zygote Service has already been
-     * started.
-     */
-    @GuardedBy("sLock")
-    private static boolean sStartedService = false;
+    private static ChildZygoteProcess sZygote;
 
     /**
      * Information about the selected WebView package. This is set from #onWebViewProviderChanged().
@@ -85,7 +72,7 @@
         synchronized (sLock) {
             if (sZygote != null) return sZygote;
 
-            waitForServiceStartAndConnect();
+            connectToZygoteIfNeededLocked();
             return sZygote;
         }
     }
@@ -107,21 +94,13 @@
             sMultiprocessEnabled = enabled;
 
             // When toggling between multi-process being on/off, start or stop the
-            // service. If it is enabled and the zygote is not yet started, bring up the service.
-            // Otherwise, bring down the service. The name may be null if the package
-            // information has not yet been resolved.
-            final String serviceName = getServiceNameLocked();
-            if (serviceName == null) return;
-
+            // zygote. If it is enabled and the zygote is not yet started, launch it.
+            // Otherwise, kill it. The name may be null if the package information has
+            // not yet been resolved.
             if (enabled) {
-                if (!sStartedService) {
-                    SystemService.start(serviceName);
-                    sStartedService = true;
-                }
+                connectToZygoteIfNeededLocked();
             } else {
-                SystemService.stop(serviceName);
-                sStartedService = false;
-                sZygote = null;
+                stopZygoteLocked();
             }
         }
     }
@@ -137,53 +116,21 @@
                 return;
             }
 
-            final String serviceName = getServiceNameLocked();
-            sZygote = null;
-
-            // The service may enter the RUNNING state before it opens the socket,
-            // so connectToZygoteIfNeededLocked() may still fail.
-            if (SystemService.isStopped(serviceName)) {
-                SystemService.start(serviceName);
-            } else {
-                SystemService.restart(serviceName);
-            }
-            sStartedService = true;
-        }
-    }
-
-    private static void waitForServiceStartAndConnect() {
-        if (!sStartedService) {
-            throw new AndroidRuntimeException("Tried waiting for the WebView Zygote Service to " +
-                    "start running without first starting the service.");
-        }
-
-        String serviceName;
-        synchronized (sLock) {
-            serviceName = getServiceNameLocked();
-        }
-        try {
-            SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
-        } catch (TimeoutException e) {
-            Log.e(LOGTAG, "Timed out waiting for " + serviceName);
-            return;
-        }
-
-        synchronized (sLock) {
-            connectToZygoteIfNeededLocked();
+            stopZygoteLocked();
         }
     }
 
     @GuardedBy("sLock")
-    private static String getServiceNameLocked() {
-        if (sPackage == null)
-            return null;
-
-        if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
-                    sPackage.applicationInfo.primaryCpuAbi)) {
-            return WEBVIEW_ZYGOTE_SERVICE_64;
+    private static void stopZygoteLocked() {
+        if (sZygote != null) {
+            // Close the connection and kill the zygote process. This will not cause
+            // child processes to be killed by itself. But if this is called in response to
+            // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater
+            // will kill all processes that depend on the WebView package.
+            sZygote.close();
+            Process.killProcess(sZygote.getPid());
+            sZygote = null;
         }
-
-        return WEBVIEW_ZYGOTE_SERVICE_32;
     }
 
     @GuardedBy("sLock")
@@ -197,14 +144,17 @@
             return;
         }
 
-        final String serviceName = getServiceNameLocked();
-        if (!SystemService.isRunning(serviceName)) {
-            Log.e(LOGTAG, serviceName + " is not running");
-            return;
-        }
-
         try {
-            sZygote = new ZygoteProcess(WEBVIEW_ZYGOTE_SOCKET, null);
+            sZygote = Process.zygoteProcess.startChildZygote(
+                    "com.android.internal.os.WebViewZygoteInit",
+                    "webview_zygote",
+                    Process.WEBVIEW_ZYGOTE_UID,
+                    Process.WEBVIEW_ZYGOTE_UID,
+                    null,  // gids
+                    0,  // runtimeFlags
+                    "webview_zygote",  // seInfo
+                    sPackage.applicationInfo.primaryCpuAbi,  // abi
+                    null);  // instructionSet
 
             // All the work below is usually done by LoadedApk, but the zygote can't talk to
             // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
@@ -226,14 +176,14 @@
             final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
                     TextUtils.join(File.pathSeparator, zipPaths);
 
-            ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
+            ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
 
             Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
             sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
                                          Build.SUPPORTED_ABIS[0]);
         } catch (Exception e) {
-            Log.e(LOGTAG, "Error connecting to " + serviceName, e);
-            sZygote = null;
+            Log.e(LOGTAG, "Error connecting to webview zygote", e);
+            stopZygoteLocked();
         }
     }
 }
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index b38c851..32b580c 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -18,9 +18,11 @@
 
 import android.app.ApplicationLoaders;
 import android.net.LocalSocket;
+import android.net.LocalServerSocket;
 import android.os.Build;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.Log;
 import android.webkit.WebViewFactory;
@@ -118,18 +120,35 @@
     }
 
     public static void main(String argv[]) {
-        sServer = new WebViewZygoteServer();
+        Log.i(TAG, "Starting WebViewZygoteInit");
 
-        // Zygote goes into its own process group.
-        try {
-            Os.setpgid(0, 0);
-        } catch (ErrnoException ex) {
-            throw new RuntimeException("Failed to setpgid(0,0)", ex);
+        String socketName = null;
+        for (String arg : argv) {
+            Log.i(TAG, arg);
+            if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+                socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
+            }
         }
+        if (socketName == null) {
+            throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
+        }
+
+        try {
+            Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+        } catch (ErrnoException ex) {
+            throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
+        }
+
+        sServer = new WebViewZygoteServer();
 
         final Runnable caller;
         try {
-            sServer.registerServerSocketFromEnv("webview_zygote");
+            sServer.registerServerSocketAtAbstractName(socketName);
+
+            // Add the abstract socket to the FD whitelist so that the native zygote code
+            // can properly detach it after forking.
+            Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
+
             // The select loop returns early in the child process after a fork and
             // loops forever in the zygote.
             caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
diff --git a/core/tests/BroadcastRadioTests/OWNERS b/core/tests/BroadcastRadioTests/OWNERS
new file mode 100644
index 0000000..ea4421e
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/OWNERS
@@ -0,0 +1,2 @@
+twasilczyk@google.com
+randolphs@google.com
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index 32d3162..231a4a5 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -88,14 +88,15 @@
         public void onItemLoaded(@NonNull String mediaId, @Nullable MediaItem2 result) { }
 
         /**
-         * Called when there's change in the search result.
+         * Called when there's change in the search result requested by the previous
+         * {@link MediaBrowser2#search(String, Bundle)}.
          *
          * @param query search query that you've specified with {@link #search(String, Bundle)}
-         * @param extras extra bundle that you've specified with {@link #search(String, Bundle)}
-         * @param totalItemCount The total item count for the search result
+         * @param extras extra bundle
+         * @param itemCount The item count for the search result
          */
         public void onSearchResultChanged(@NonNull String query, @Nullable Bundle extras,
-                int totalItemCount) { }
+                int itemCount) { }
 
         /**
          * Called when the search result has been returned by the library service for the previous
@@ -189,10 +190,9 @@
     }
 
     /**
-     * Send a search request to the library service. When there's a change,
-     * {@link BrowserCallback#onSearchResultChanged(String, Bundle, int)} will be called with the
-     * bundle that you've specified. You should call
-     * {@link #getSearchResult(String, int, int, Bundle)} to get the actual search result.
+     * Send a search request to the library service. When the search result is changed,
+     * {@link BrowserCallback#onSearchResultChanged(String, Bundle, int)} will be called. You should
+     * call {@link #getSearchResult(String, int, int, Bundle)} to get the actual search result.
      *
      * @param query search query. Should not be an empty string.
      * @param extras extra bundle
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index bd6c7e6..bfd1fd4 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -570,14 +570,14 @@
     }
 
     /**
-     * Rate the current content. This will cause the rating to be set for
-     * the current user. The Rating type must match the type returned by
-     * {@link #getRatingType()}.
+     * Rate the media. This will cause the rating to be set for the current user.
+     * The Rating type must match the type returned by {@link #getRatingType()}.
      *
-     * @param rating The rating to set for the current content
+     * @param mediaId The id of the media
+     * @param rating The rating to set
      */
-    public void setRating(Rating2 rating) {
-        mProvider.setRating_impl(rating);
+    public void setRating(String mediaId, Rating2 rating) {
+        mProvider.setRating_impl(mediaId, rating);
     }
 
     /**
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 7a05d3c..95d83ee 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -99,6 +99,19 @@
         public void notifyChildrenChanged(@NonNull String parentId, @Nullable Bundle extras) {
             mProvider.notifyChildrenChanged_impl(parentId, extras);
         }
+
+        /**
+         * Notify controller about change in the search result.
+         *
+         * @param controller controller to notify
+         * @param query previously sent search query from the controller.
+         * @param extras extra bundle
+         * @param itemCount the number of items that have been found in the search.
+         */
+        public void notifySearchResultChanged(@NonNull ControllerInfo controller,
+                @NonNull String query, @NonNull Bundle extras, int itemCount) {
+            mProvider.notifySearchResultChanged_impl(controller, query, extras, itemCount);
+        }
     }
 
     /**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 943b827..0258dca 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -452,13 +452,15 @@
         }
 
         /**
-         * Called when a controller set rating on the currently playing contents by
-         * {@link MediaController2#setRating(Rating2)}.
+         * Called when a controller set rating of a media item through
+         * {@link MediaController2#setRating(String, Rating2)}.
          *
          * @param controller controller information
+         * @param mediaId media id from the controller
          * @param rating new rating from the controller
          */
-        public void onSetRating(@NonNull ControllerInfo controller, @NonNull Rating2 rating) { }
+        public void onSetRating(@NonNull ControllerInfo controller, @NonNull String mediaId,
+                @NonNull Rating2 rating) { }
 
         /**
          * Called when a controller sent a custom command through
diff --git a/media/java/android/media/update/MediaBrowser2Provider.java b/media/java/android/media/update/MediaBrowser2Provider.java
index f2e7313..eda4c7c 100644
--- a/media/java/android/media/update/MediaBrowser2Provider.java
+++ b/media/java/android/media/update/MediaBrowser2Provider.java
@@ -24,11 +24,11 @@
 public interface MediaBrowser2Provider extends MediaController2Provider {
     void getLibraryRoot_impl(Bundle rootHints);
 
-    void subscribe_impl(String parentId, Bundle options);
-    void unsubscribe_impl(String parentId, Bundle options);
+    void subscribe_impl(String parentId, Bundle extras);
+    void unsubscribe_impl(String parentId, Bundle extras);
 
     void getItem_impl(String mediaId);
     void getChildren_impl(String parentId, int page, int pageSize, Bundle extras);
-    void search_impl(String query, Bundle options);
+    void search_impl(String query, Bundle extras);
     void getSearchResult_impl(String query, int page, int pageSize, Bundle extras);
 }
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index c492d307..738bd0c 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -56,7 +56,7 @@
     void playFromUri_impl(Uri uri, Bundle extras);
     void playFromMediaId_impl(String mediaId, Bundle extras);
 
-    void setRating_impl(Rating2 rating);
+    void setRating_impl(String mediaId, Rating2 rating);
     void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb);
     List<MediaItem2> getPlaylist_impl();
 
diff --git a/media/java/android/media/update/MediaLibraryService2Provider.java b/media/java/android/media/update/MediaLibraryService2Provider.java
index 923551a..d837833 100644
--- a/media/java/android/media/update/MediaLibraryService2Provider.java
+++ b/media/java/android/media/update/MediaLibraryService2Provider.java
@@ -30,8 +30,10 @@
     // Nothing new for now
 
     interface MediaLibrarySessionProvider extends MediaSession2Provider {
-        void notifyChildrenChanged_impl(ControllerInfo controller, String parentId, Bundle options);
-        void notifyChildrenChanged_impl(String parentId, Bundle options);
+        void notifyChildrenChanged_impl(ControllerInfo controller, String parentId, Bundle extras);
+        void notifyChildrenChanged_impl(String parentId, Bundle extras);
+        void notifySearchResultChanged_impl(ControllerInfo controller, String query, Bundle extras,
+                int itemCount);
     }
 
     interface LibraryRootProvider {
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
deleted file mode 100644
index 4a77af9..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/fingerprint_dialog_bg_color" />
-    <corners android:radius="1dp"
-        android:topLeftRadius="16dp"
-        android:topRightRadius="16dp"
-        android:bottomLeftRadius="0dp"
-        android:bottomRightRadius="0dp"/>
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/fingerprint_dialog.xml
index 161f13f..f02c0ba 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -35,131 +35,105 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:elevation="2dp"
-        android:background="@drawable/fingerprint_dialog_bg">
+        android:background="@color/fingerprint_dialog_bg_color">
 
-        <RelativeLayout
+        <TextView
+            android:id="@+id/title"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:elevation="2dp">
+            android:layout_marginEnd="24dp"
+            android:layout_marginStart="24dp"
+            android:layout_marginTop="24dp"
+            android:gravity="center"
+            android:textSize="20sp"
+            android:maxLines="1"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:textColor="@color/fingerprint_dialog_text_dark_color"/>
 
-            <ImageView
-                android:id="@+id/icon"
-                android:layout_width="@dimen/fingerprint_dialog_icon_size"
-                android:layout_height="@dimen/fingerprint_dialog_icon_size"
-                android:layout_marginTop="16dp"
-                android:layout_marginStart="16dp"
-                android:scaleType="centerInside" />
-
-            <TextView
-                android:id="@+id/title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_toRightOf="@+id/icon"
-                android:layout_marginEnd="16dp"
-                android:layout_marginStart="16dp"
-                android:layout_marginTop="16dp"
-                android:textSize="20sp"
-                android:maxLines="1"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:marqueeRepeatLimit="marquee_forever"
-                android:textColor="@color/fingerprint_dialog_text_color"/>
-
-            <TextView
-                android:id="@+id/subtitle"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_toRightOf="@+id/icon"
-                android:layout_below="@+id/title"
-                android:layout_marginEnd="16dp"
-                android:layout_marginStart="16dp"
-                android:layout_marginTop="4dp"
-                android:textSize="12sp"
-                android:maxLines="2"
-                android:textColor="@color/fingerprint_dialog_text_color"/>
-
-        </RelativeLayout>
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:layout_marginStart="24dp"
+            android:layout_marginEnd="24dp"
+            android:gravity="center_horizontal"
+            android:textSize="14sp"
+            android:maxLines="1"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:textColor="@color/fingerprint_dialog_text_light_color"/>
 
         <TextView
             android:id="@+id/description"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginEnd="16dp"
-            android:layout_marginStart="16dp"
-            android:paddingTop="16dp"
-            android:paddingBottom="20dp"
+            android:layout_marginEnd="24dp"
+            android:layout_marginStart="24dp"
+            android:paddingTop="24dp"
             android:textSize="16sp"
             android:maxLines="4"
-            android:textColor="@color/fingerprint_dialog_text_color"/>
+            android:textColor="@color/fingerprint_dialog_text_dark_color"/>
 
         <ImageView
             android:id="@+id/fingerprint_icon"
             android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
             android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
             android:layout_gravity="center_horizontal"
-            android:scaleType="centerInside"
-            android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon"
-            android:src="@drawable/fingerprint_icon"/>
+            android:layout_marginTop="32dp"
+            android:scaleType="fitXY"
+            android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
 
         <TextView
             android:id="@+id/error"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginEnd = "16dp"
-            android:layout_marginStart="16dp"
+            android:layout_marginEnd="24dp"
+            android:layout_marginStart="24dp"
             android:paddingTop="16dp"
-            android:paddingBottom="60dp"
+            android:paddingBottom="24dp"
             android:textSize="12sp"
-            android:visibility="invisible"
             android:gravity="center_horizontal"
             android:accessibilityLiveRegion="polite"
+            android:text="@string/fingerprint_dialog_touch_sensor"
             android:contentDescription="@string/accessibility_fingerprint_dialog_help_area"
-            android:textColor="@color/fingerprint_error_message_color"/>
+            android:textColor="@color/fingerprint_dialog_text_light_color"/>
 
-        <LinearLayout android:id="@+id/buttonPanel"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="54dip"
-            android:orientation="vertical" >
-            <LinearLayout
-                style="?android:attr/buttonBarStyle"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                android:paddingTop="4dip"
-                android:paddingStart="2dip"
-                android:paddingEnd="2dip"
-                android:measureWithLargestChild="true">
-                <LinearLayout android:id="@+id/leftSpacer"
-                    android:layout_weight="0.25"
-                    android:layout_width="0dip"
-                    android:layout_height="wrap_content"
-                    android:orientation="horizontal"
-                    android:visibility="gone" />
-                <!-- Positive Button -->
-                <Button android:id="@+id/button1"
-                    android:layout_width="0dip"
-                    android:layout_gravity="start"
-                    android:layout_weight="1"
-                    style="?android:attr/buttonBarButtonStyle"
-                    android:maxLines="2"
-                    android:layout_height="wrap_content"/>
-                <!-- Negative Button -->
-                <Button android:id="@+id/button2"
-                    android:layout_width="0dip"
-                    android:layout_gravity="end"
-                    android:layout_weight="1"
-                    style="?android:attr/buttonBarButtonStyle"
-                    android:maxLines="2"
-                    android:layout_height="wrap_content" />
-                <LinearLayout android:id="@+id/rightSpacer"
-                    android:layout_width="0dip"
-                    android:layout_weight="0.25"
-                    android:layout_height="wrap_content"
-                    android:orientation="horizontal"
-                    android:visibility="gone" />
-            </LinearLayout>
+            android:layout_height="72dip"
+            android:paddingTop="16dp"
+            android:layout_gravity="center_vertical"
+            style="?android:attr/buttonBarStyle"
+            android:orientation="horizontal"
+            android:measureWithLargestChild="true">
+            <Space android:id="@+id/leftSpacer"
+                android:layout_width="24dp"
+                android:layout_height="match_parent"
+                android:visibility="visible" />
+            <!-- Negative Button -->
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                android:layout_marginStart="-12dp"
+                android:gravity="start|center_vertical"
+                android:maxLines="2" />
+            <!-- Positive Button -->
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                android:layout_marginEnd="12dp"
+                android:maxLines="2" />
+            <Space android:id="@+id/rightSpacer"
+                android:layout_width="24dip"
+                android:layout_height="match_parent"
+                android:visibility="gone" />
         </LinearLayout>
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c054d16..e2a94df 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -161,9 +161,11 @@
 
     <!-- Fingerprint dialog colors -->
     <color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
-    <color name="fingerprint_dialog_text_color">#ff424242</color> <!-- gray 800-->
+    <color name="fingerprint_dialog_text_dark_color">#ff212121</color>
+    <color name="fingerprint_dialog_text_light_color">#ff757575</color>
     <color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
-    <color name="fingerprint_error_message_color">#ff5722</color>
+    <color name="fingerprint_dialog_error_message_color">#ffff5722</color>
+    <color name="fingerprint_dialog_fingerprint_color">#ff009688</color>
 
     <!-- Logout button -->
     <color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3ff553e..e679fcd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -895,7 +895,7 @@
     <dimen name="smart_reply_button_font_size">14sp</dimen>
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
 
-    <dimen name="fingerprint_dialog_icon_size">44dp</dimen>
+    <!-- Fingerprint Dialog values -->
     <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
     <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8c59e75..0b5b7bd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -259,6 +259,8 @@
     <!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
     <string name="cancel">Cancel</string>
 
+    <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
+    <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string>
     <!-- Content description of the application icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 262c71a..1d43b1d 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -211,7 +211,7 @@
     }
 
     private void handleClearMessage() {
-        mDialogView.clearMessage();
+        mDialogView.resetMessage();
     }
 
     private void handleUserCanceled() {
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 9779937..e828b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -16,17 +16,18 @@
 
 package com.android.systemui.fingerprint;
 
-import android.app.ActivityManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
+import android.graphics.Color;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.fingerprint.FingerprintDialog;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -41,8 +42,6 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.PackageManagerWrapper;
 
 /**
  * This class loads the view for the system-provided dialog. The view consists of:
@@ -55,28 +54,39 @@
 
     private static final int ANIMATION_DURATION = 250; // ms
 
+    private static final int STATE_NONE = 0;
+    private static final int STATE_FINGERPRINT = 1;
+    private static final int STATE_FINGERPRINT_ERROR = 2;
+    private static final int STATE_FINGERPRINT_AUTHENTICATED = 3;
+
     private final IBinder mWindowToken = new Binder();
-    private final ActivityManagerWrapper mActivityManagerWrapper;
-    private final PackageManagerWrapper mPackageManageWrapper;
     private final Interpolator mLinearOutSlowIn;
     private final Interpolator mFastOutLinearIn;
     private final float mAnimationTranslationOffset;
+    private final int mErrorTextColor;
+    private final int mTextColor;
+    private final int mFingerprintColor;
 
     private ViewGroup mLayout;
     private final TextView mErrorText;
     private Handler mHandler;
     private Bundle mBundle;
     private final LinearLayout mDialog;
+    private int mLastState;
 
     public FingerprintDialogView(Context context, Handler handler) {
         super(context);
         mHandler = handler;
-        mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
-        mPackageManageWrapper = PackageManagerWrapper.getInstance();
         mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
         mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
         mAnimationTranslationOffset = getResources()
                 .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
+        mErrorTextColor = Color.parseColor(
+                getResources().getString(R.color.fingerprint_dialog_error_message_color));
+        mTextColor = Color.parseColor(
+                getResources().getString(R.color.fingerprint_dialog_text_light_color));
+        mFingerprintColor = Color.parseColor(
+                getResources().getString(R.color.fingerprint_dialog_fingerprint_color));
 
         // Create the dialog
         LayoutInflater factory = LayoutInflater.from(getContext());
@@ -112,7 +122,7 @@
 
         space.setClickable(true);
         space.setOnTouchListener((View view, MotionEvent event) -> {
-            mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled*/)
+            mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled */)
                     .sendToTarget();
             return true;
         });
@@ -137,16 +147,16 @@
         final TextView subtitle = mLayout.findViewById(R.id.subtitle);
         final TextView description = mLayout.findViewById(R.id.description);
         final Button negative = mLayout.findViewById(R.id.button2);
-        final ImageView image = mLayout.findViewById(R.id.icon);
         final Button positive = mLayout.findViewById(R.id.button1);
-        final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
+
+        mLastState = STATE_NONE;
+        updateFingerprintIcon(STATE_FINGERPRINT);
 
         title.setText(mBundle.getCharSequence(FingerprintDialog.KEY_TITLE));
         title.setSelected(true);
         subtitle.setText(mBundle.getCharSequence(FingerprintDialog.KEY_SUBTITLE));
         description.setText(mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION));
         negative.setText(mBundle.getCharSequence(FingerprintDialog.KEY_NEGATIVE_TEXT));
-        setAppIcon(image);
 
         final CharSequence positiveText =
                 mBundle.getCharSequence(FingerprintDialog.KEY_POSITIVE_TEXT);
@@ -183,39 +193,75 @@
         mBundle = bundle;
     }
 
-    protected void clearMessage() {
-        mErrorText.setVisibility(View.INVISIBLE);
+    // Clears the temporary message and shows the help message.
+    protected void resetMessage() {
+        updateFingerprintIcon(STATE_FINGERPRINT);
+        mErrorText.setText(R.string.fingerprint_dialog_touch_sensor);
+        mErrorText.setTextColor(mTextColor);
     }
 
-    private void showMessage(String message) {
+    // Shows an error/help message
+    private void showTemporaryMessage(String message) {
         mHandler.removeMessages(FingerprintDialogImpl.MSG_CLEAR_MESSAGE);
+        updateFingerprintIcon(STATE_FINGERPRINT_ERROR);
         mErrorText.setText(message);
+        mErrorText.setTextColor(mErrorTextColor);
         mErrorText.setContentDescription(message);
-        mErrorText.setVisibility(View.VISIBLE);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
                 FingerprintDialog.HIDE_DIALOG_DELAY);
     }
 
     public void showHelpMessage(String message) {
-        showMessage(message);
+        showTemporaryMessage(message);
     }
 
     public void showErrorMessage(String error) {
-        showMessage(error);
+        showTemporaryMessage(error);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
                 false /* userCanceled */), FingerprintDialog.HIDE_DIALOG_DELAY);
     }
 
-    private void setAppIcon(ImageView image) {
-        final ActivityManager.RunningTaskInfo taskInfo = mActivityManagerWrapper.getRunningTask();
-        final ComponentName cn = taskInfo.topActivity;
-        final int userId = mActivityManagerWrapper.getCurrentUserId();
-        final ActivityInfo activityInfo = mPackageManageWrapper.getActivityInfo(cn, userId);
-        image.setImageDrawable(mActivityManagerWrapper.getBadgedActivityIcon(activityInfo, userId));
-        image.setContentDescription(
-                getResources().getString(R.string.accessibility_fingerprint_dialog_app_icon)
-                        + " "
-                        + mActivityManagerWrapper.getBadgedActivityLabel(activityInfo, userId));
+    private void updateFingerprintIcon(int newState) {
+        Drawable icon  = getAnimationResForTransition(mLastState, newState);
+
+        if (icon == null) {
+            Log.e(TAG, "Animation not found");
+            return;
+        }
+
+        if (newState == STATE_FINGERPRINT) {
+            icon.setColorFilter(mFingerprintColor, PorterDuff.Mode.SRC_IN);
+        }
+
+        final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
+                ? (AnimatedVectorDrawable) icon
+                : null;
+
+        final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
+        fingerprint_icon.setImageDrawable(icon);
+
+        if (animation != null) {
+            animation.forceAnimationOnUI();
+            animation.start();
+        }
+
+        mLastState = newState;
+    }
+
+    private Drawable getAnimationResForTransition(int oldState, int newState) {
+        int iconRes;
+        if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
+            iconRes = R.drawable.lockscreen_fingerprint_draw_on_animation;
+        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+            iconRes = R.drawable.lockscreen_fingerprint_fp_to_error_state_animation;
+        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
+            iconRes = R.drawable.lockscreen_fingerprint_error_state_to_fp_animation;
+        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
+            iconRes = R.drawable.lockscreen_fingerprint_draw_off_animation;
+        } else {
+            return null;
+        }
+        return mContext.getDrawable(iconRes);
     }
 
     public WindowManager.LayoutParams getLayoutParams() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 89cc509..26fac6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -211,11 +211,13 @@
     }
 
     /**
-     * @return True unless setprop has been set to false, or we're in demo mode.
+     * @return True unless setprop has been set to false, we're in demo mode, or running tests in
+     * automation.
      */
     private boolean shouldShow() {
         return SystemProperties.getBoolean("persist.quickstep.onboarding.enabled",
-                !(mContext.getSystemService(UserManager.class)).isDemoUser());
+                !(mContext.getSystemService(UserManager.class)).isDemoUser() &&
+                !ActivityManager.isRunningInTestHarness());
     }
 
     public void hide(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 4454ef9..57d78dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -88,7 +88,7 @@
         @Override
         public void onRecentsAnimationStarted() {
             mRecentsAnimationStarted = true;
-            mQuickScrubController.cancelQuickSwitch();
+            mQuickScrubController.setRecentsAnimationStarted(true /* started */);
         }
     };
 
@@ -163,6 +163,7 @@
                 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
                 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                 mRecentsAnimationStarted = false;
+                mQuickScrubController.setRecentsAnimationStarted(false /* started */);
                 break;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index 378858a..dc0ea1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -75,6 +75,7 @@
     private boolean mDraggingActive;
     private boolean mQuickScrubActive;
     private boolean mAllowQuickSwitch;
+    private boolean mRecentsAnimationStarted;
     private float mDownOffset;
     private float mTranslation;
     private int mTouchDownX;
@@ -279,7 +280,7 @@
                     }
 
                     // Control the button movement
-                    if (!mDraggingActive && exceededTouchSlop) {
+                    if (!mDraggingActive && exceededTouchSlop && !mRecentsAnimationStarted) {
                         boolean allowDrag = !mDragPositive
                                 ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
                         if (allowDrag) {
@@ -417,6 +418,13 @@
         mDraggingActive = false;
     }
 
+    public void setRecentsAnimationStarted(boolean started) {
+        mRecentsAnimationStarted = started;
+        if (started) {
+            cancelQuickSwitch();
+        }
+    }
+
     public void cancelQuickSwitch() {
         mAllowQuickSwitch = false;
         mHandler.removeCallbacks(mLongPressRunnable);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 7cd007b..1d5e47a 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -4702,6 +4702,10 @@
         @ShellCommandResult
         @Override
         public int onCommand(@Nullable String cmd) {
+            if ("refresh_debug_properties".equals(cmd)) {
+                return refreshDebugProperties();
+            }
+
             // For existing "adb shell ime <command>".
             if ("ime".equals(cmd)) {
                 final String imeCommand = getNextArg();
@@ -4720,8 +4724,6 @@
                         return mService.handleShellCommandSetInputMethod(this);
                     case "reset":
                         return mService.handleShellCommandResetInputMethod(this);
-                    case "refresh_debug_properties":
-                        return refreshDebugProperties();
                     default:
                         getOutPrintWriter().println("Unknown command: " + imeCommand);
                         return ShellCommandResult.FAILURE;
diff --git a/services/core/java/com/android/server/broadcastradio/OWNERS b/services/core/java/com/android/server/broadcastradio/OWNERS
new file mode 100644
index 0000000..ea4421e
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/OWNERS
@@ -0,0 +1,2 @@
+twasilczyk@google.com
+randolphs@google.com
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 05c7f19..52f5917 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -2261,7 +2261,12 @@
                     Slog.i(TAG, "Moving uid " + uid + " to bucketIndex " + bucketIndex);
                 }
                 synchronized (mLock) {
-                    mJobs.forEachJobForSourceUid(uid, job -> job.setStandbyBucket(bucketIndex));
+                    mJobs.forEachJobForSourceUid(uid, job -> {
+                        // double-check uid vs package name to disambiguate shared uids
+                        if (packageName.equals(job.getSourcePackageName())) {
+                            job.setStandbyBucket(bucketIndex);
+                        }
+                    });
                     onControllerStateChanged();
                 }
             });
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 23a66ba..5460756 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -570,12 +570,6 @@
             throws RemoteException, ServiceSpecificException {
         byte[] locallyEncryptedKey;
         try {
-            // TODO: Remove the extraneous logging here
-            Log.d(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()",
-                    sessionEntry.getKeyClaimant()));
-            Log.d(TAG, constructLoggingMessage("sessionEntry.getVaultParams()",
-                    sessionEntry.getVaultParams()));
-            Log.d(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse));
             locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse(
                     sessionEntry.getKeyClaimant(),
                     sessionEntry.getVaultParams(),
@@ -594,10 +588,6 @@
         }
 
         try {
-            // TODO: Remove the extraneous logging here
-            Log.d(TAG, constructLoggingMessage("sessionEntry.getLskfHash()",
-                    sessionEntry.getLskfHash()));
-            Log.d(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey));
             return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey);
         } catch (InvalidKeyException e) {
             Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e);
@@ -636,9 +626,6 @@
             byte[] encryptedKeyMaterial = applicationKey.getEncryptedKeyMaterial();
 
             try {
-                // TODO: Remove the extraneous logging here
-                Log.d(TAG, constructLoggingMessage("recoveryKey", recoveryKey));
-                Log.d(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial));
                 byte[] keyMaterial =
                         KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
                 keyMaterialByAlias.put(alias, keyMaterial);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4b80e98..32e15c9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -152,7 +152,8 @@
  */
 public class NetworkStatsService extends INetworkStatsService.Stub {
     static final String TAG = "NetworkStats";
-    static final boolean LOGV = false;
+    static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
+    static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final int MSG_PERFORM_POLL = 1;
     private static final int MSG_UPDATE_IFACES = 2;
@@ -641,14 +642,14 @@
         if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
                 && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL)
                 && mSettings.getAugmentEnabled()) {
-            Slog.d(TAG, "Resolving plan for " + template);
+            if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
             final long token = Binder.clearCallingIdentity();
             try {
                 final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
                 final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
                 for (int subId : sm.getActiveSubscriptionIdList()) {
                     if (template.matchesSubscriberId(tm.getSubscriberId(subId))) {
-                        Slog.d(TAG, "Found active matching subId " + subId);
+                        if (LOGD) Slog.d(TAG, "Found active matching subId " + subId);
                         final List<SubscriptionPlan> plans = sm.getSubscriptionPlans(subId);
                         if (!plans.isEmpty()) {
                             plan = plans.get(0);
@@ -658,7 +659,7 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
-            Slog.d(TAG, "Resolved to plan " + plan);
+            if (LOGD) Slog.d(TAG, "Resolved to plan " + plan);
         }
         return plan;
     }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3d60ee4..a4f20b01 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -204,9 +204,20 @@
     }
 
     DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+        final int displayId = display.getDisplayId();
+
+        // In select scenarios, it is possible that a DisplayContent will be created on demand
+        // rather than waiting for the controller. In this case, associate the controller and return
+        // the existing display.
+        final DisplayContent existing = getDisplayContent(displayId);
+
+        if (existing != null) {
+            existing.setController(controller);
+            return existing;
+        }
+
         final DisplayContent dc =
                 new DisplayContent(display, mService, mWallpaperController, controller);
-        final int displayId = display.getDisplayId();
 
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ace0944..26ac79e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1131,7 +1131,18 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+
+            // Adding a window is an exception where the WindowManagerService can create the
+            // display instead of waiting for the ActivityManagerService to drive creation.
+            if (displayContent == null) {
+                final Display display = mDisplayManager.getDisplay(displayId);
+
+                if (display != null) {
+                    displayContent = mRoot.createDisplayContent(display, null /* controller */);
+                }
+            }
+
             if (displayContent == null) {
                 Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                         + displayId + ".  Aborting.");
diff --git a/services/core/jni/BroadcastRadio/OWNERS b/services/core/jni/BroadcastRadio/OWNERS
new file mode 100644
index 0000000..ea4421e
--- /dev/null
+++ b/services/core/jni/BroadcastRadio/OWNERS
@@ -0,0 +1,2 @@
+twasilczyk@google.com
+randolphs@google.com
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
index 353a68f..17a4d34 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
@@ -176,7 +176,6 @@
                 () -> reader.readProtectionParams());
     }
 
-    @Ignore("Investigate why this is broken. b/73609806")
     @Test
     public void testKeyChainSnapshot() throws Exception {
         PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
@@ -201,7 +200,7 @@
         KeyChainSnapshot snapshot =  new KeyChainSnapshot.Builder()
                 .setSnapshotVersion(SNAPSHOT_VERSION)
                 .setKeyChainProtectionParams(protectionParamsList)
-                .setEncryptedRecoveryKeyBlob(KEY_MATERIAL)
+                .setEncryptedRecoveryKeyBlob(RECOVERY_KEY_MATERIAL)
                 .setWrappedApplicationKeys(appKeysList)
                 .setMaxAttempts(MAX_ATTEMPTS)
                 .setCounterId(COUNTER_ID)
@@ -218,13 +217,11 @@
 
         KeyChainSnapshot copy = reader.readKeyChainSnapshot();
         assertThat(copy.getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION);
-        assertThat(copy.getKeyChainProtectionParams()).hasSize(2);
+        assertThat(copy.getKeyChainProtectionParams()).hasSize(1);
         assertThat(copy.getKeyChainProtectionParams().get(0).getUserSecretType()).isEqualTo(1);
-        assertThat(copy.getKeyChainProtectionParams().get(1).getUserSecretType()).isEqualTo(2);
         assertThat(copy.getEncryptedRecoveryKeyBlob()).isEqualTo(RECOVERY_KEY_MATERIAL);
-        assertThat(copy.getWrappedApplicationKeys()).hasSize(2);
+        assertThat(copy.getWrappedApplicationKeys()).hasSize(1);
         assertThat(copy.getWrappedApplicationKeys().get(0).getAlias()).isEqualTo(ALIAS);
-        assertThat(copy.getWrappedApplicationKeys().get(1).getAlias()).isEqualTo(ALIAS2);
         assertThat(copy.getMaxAttempts()).isEqualTo(MAX_ATTEMPTS);
         assertThat(copy.getCounterId()).isEqualTo(COUNTER_ID);
         assertThat(copy.getServerParams()).isEqualTo(SERVER_PARAMS);
@@ -237,7 +234,6 @@
         verifyDeserialize(snapshot);
     }
 
-    @Ignore("Investigate why this is broken. b/73609806")
     @Test
     public void testKeyChainSnapshot_withManyKeysAndProtectionParams() throws Exception {
         PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
@@ -272,7 +268,7 @@
         KeyChainSnapshot snapshot =  new KeyChainSnapshot.Builder()
                 .setSnapshotVersion(SNAPSHOT_VERSION)
                 .setKeyChainProtectionParams(protectionParamsList)
-                .setEncryptedRecoveryKeyBlob(KEY_MATERIAL)
+                .setEncryptedRecoveryKeyBlob(RECOVERY_KEY_MATERIAL)
                 .setWrappedApplicationKeys(appKeysList)
                 .setMaxAttempts(MAX_ATTEMPTS)
                 .setCounterId(COUNTER_ID)