Merge "Added TestApi to ActivityInfo.isTranslucentOrFloating" into pi-dev
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index 37b7acf..8683ca1 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -211,10 +211,10 @@
                 mExtras.putBoolean(key, Boolean.valueOf(value));
 
             } else if (opt.equals("-f") || opt.equals("--foreground")) {
-                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE;
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
 
             } else if (opt.equals("-F") || opt.equals("--top")) {
-                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
 
             } else {
                 System.err.println("Error: Unknown option: " + opt);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 4909690..9355862 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -741,6 +741,7 @@
 Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
 Landroid/app/IWallpaperManager;->getWallpaperInfo(I)Landroid/app/WallpaperInfo;
 Landroid/app/IWallpaperManager;->getWidthHint()I
+Landroid/app/IWallpaperManager;->hasNamedWallpaper(Ljava/lang/String;)Z
 Landroid/app/IWallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;)V
 Landroid/app/IWallpaperManagerCallback$Stub;-><init>()V
 Landroid/app/IWallpaperManagerCallback;->onWallpaperChanged()V
@@ -923,6 +924,7 @@
 Landroid/app/ServiceConnectionLeaked;-><init>(Ljava/lang/String;)V
 Landroid/app/SharedPreferencesImpl;-><init>(Ljava/io/File;I)V
 Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File;
+Landroid/app/SharedPreferencesImpl;->startLoadFromDisk()V
 Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V
 Landroid/app/StatusBarManager;-><init>(Landroid/content/Context;)V
 Landroid/app/StatusBarManager;->collapsePanels()V
@@ -5116,6 +5118,7 @@
 Landroid/service/wallpaper/WallpaperService$Engine;->mPendingXOffset:F
 Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
 Landroid/service/wallpaper/WallpaperService;->MSG_WINDOW_RESIZED:I
+Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
 Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
 Landroid/speech/tts/TextToSpeech;->mConnectingServiceConnection:Landroid/speech/tts/TextToSpeech$Connection;
 Landroid/speech/tts/TextToSpeech;->mCurrentEngine:Ljava/lang/String;
@@ -5433,6 +5436,7 @@
 Landroid/telephony/SmsMessage;->setSubId(I)V
 Landroid/telephony/SmsMessage;->useCdmaFormatForMoSms()Z
 Landroid/telephony/SmsMessage;->useCdmaFormatForMoSms(I)Z
+Landroid/telephony/SubscriptionInfo;->getNameSource()I
 Landroid/telephony/SubscriptionManager;-><init>(Landroid/content/Context;)V
 Landroid/telephony/SubscriptionManager;->CONTENT_URI:Landroid/net/Uri;
 Landroid/telephony/SubscriptionManager;->DEFAULT_SUBSCRIPTION_ID:I
@@ -5469,6 +5473,8 @@
 Landroid/telephony/TelephonyManager;->getDeviceSoftwareVersion(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getGroupIdLevel1(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIccAuthentication(IIILjava/lang/String;)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getImsConfig(II)Landroid/telephony/ims/aidl/IImsConfig;
+Landroid/telephony/TelephonyManager;->getImsRegistration(II)Landroid/telephony/ims/aidl/IImsRegistration;
 Landroid/telephony/TelephonyManager;->getIsimImpi()Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIsimImpu()[Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIsimPcscf()[Ljava/lang/String;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 54cb095..8d56c3e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6601,22 +6601,33 @@
      * Helper class for generating large-format notifications that include multiple back-and-forth
      * messages of varying types between any number of people.
      *
-     * <br>
+     * <p>
      * If the platform does not provide large-format notifications, this method has no effect. The
      * user will always see the normal notification view.
-     * <br>
-     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like
-     * so:
+     *
+     * <p>
+     * If the app is targeting Android P and above, it is required to use the {@link Person}
+     * class in order to get an optimal rendering of the notification and its avatars. For
+     * conversations involving multiple people, the app should also make sure that it marks the
+     * conversation as a group with {@link #setGroupConversation(boolean)}.
+     *
+     * <p>
+     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior.
+     * Here's an example of how this may be used:
      * <pre class="prettyprint">
      *
+     * Person user = new Person.Builder().setIcon(userIcon).setName(userName).build();
+     * MessagingStyle style = new MessagingStyle(user)
+     *      .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
+     *      .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
+     *      .setGroupConversation(hasMultiplePeople());
+     *
      * Notification noti = new Notification.Builder()
-     *     .setContentTitle(&quot;2 new messages wtih &quot; + sender.toString())
+     *     .setContentTitle(&quot;2 new messages with &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_message)
      *     .setLargeIcon(aBitmap)
-     *     .setStyle(new Notification.MessagingStyle(resources.getString(R.string.reply_name))
-     *         .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender())
-     *         .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender()))
+     *     .setStyle(style)
      *     .build();
      * </pre>
      */
@@ -6826,7 +6837,9 @@
         }
 
         /**
-         * Sets whether this conversation notification represents a group.
+         * Sets whether this conversation notification represents a group. If the app is targeting
+         * Android P, this is required if the app wants to display the largeIcon set with
+         * {@link Notification.Builder#setLargeIcon(Bitmap)}, otherwise it will be hidden.
          *
          * @param isGroupConversation {@code true} if the conversation represents a group,
          * {@code false} otherwise.
@@ -7048,12 +7061,21 @@
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
-            boolean isOneToOne = TextUtils.isEmpty(conversationTitle);
+            boolean atLeastP = mBuilder.mContext.getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.P;
+            boolean isOneToOne;
             CharSequence nameReplacement = null;
-            if (hasOnlyWhiteSpaceSenders()) {
-                isOneToOne = true;
-                nameReplacement = conversationTitle;
-                conversationTitle = null;
+            Icon avatarReplacement = null;
+            if (!atLeastP) {
+                isOneToOne = TextUtils.isEmpty(conversationTitle);
+                avatarReplacement = mBuilder.mN.mLargeIcon;
+                if (hasOnlyWhiteSpaceSenders()) {
+                    isOneToOne = true;
+                    nameReplacement = conversationTitle;
+                    conversationTitle = null;
+                }
+            } else {
+                isOneToOne = !isGroupConversation();
             }
             TemplateBindResult bindResult = new TemplateBindResult();
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
@@ -7076,8 +7098,8 @@
                     mBuilder.getSecondaryTextColor());
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
                     displayImagesAtEnd);
-            contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
-                    mBuilder.mN.mLargeIcon);
+            contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement",
+                    avatarReplacement);
             contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
                     nameReplacement);
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne",
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 5e75841..4c22c94 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -15,6 +15,8 @@
  */
 package android.app.slice;
 
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+
 import android.annotation.NonNull;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -29,6 +31,7 @@
 import android.content.pm.ProviderInfo;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -39,6 +42,8 @@
 import android.os.StrictMode.ThreadPolicy;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -472,12 +477,25 @@
         }
         Slice.Builder parent = new Slice.Builder(sliceUri);
         Slice.Builder childAction = new Slice.Builder(parent)
+                .addIcon(Icon.createWithResource(context,
+                        com.android.internal.R.drawable.ic_permission), null,
+                        Collections.emptyList())
                 .addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT))
                 .addAction(action, new Slice.Builder(parent).build(), null);
 
+        TypedValue tv = new TypedValue();
+        new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light)
+                .getTheme().resolveAttribute(android.R.attr.colorAccent, tv, true);
+        int deviceDefaultAccent = tv.data;
+
         parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
+                .addIcon(Icon.createWithResource(context,
+                        com.android.internal.R.drawable.ic_arrow_forward), null,
+                        Collections.emptyList())
                 .addText(getPermissionString(context, callingPackage), null,
                         Collections.emptyList())
+                .addInt(deviceDefaultAccent, SUBTYPE_COLOR,
+                        Collections.emptyList())
                 .addSubSlice(childAction.build(), null)
                 .build(), null);
         return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build();
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 1b07784..72d209a 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -184,7 +184,11 @@
     /** @hide */
     public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;
     /** @hide */
-    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B;
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
 
     /** @hide */
     public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;
@@ -669,13 +673,19 @@
                         sb.append("-sa");
                         break;
                     case REASON_SUB_USAGE_SLICE_PINNED:
-                        sb.append("slp");
+                        sb.append("-lp");
                         break;
                     case REASON_SUB_USAGE_SLICE_PINNED_PRIV:
-                        sb.append("slpp");
+                        sb.append("-lv");
+                        break;
+                    case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE:
+                        sb.append("-en");
+                        break;
+                    case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE:
+                        sb.append("-ed");
                         break;
                     case REASON_SUB_USAGE_EXEMPTED_SYNC_START:
-                        sb.append("es");
+                        sb.append("-es");
                         break;
                 }
                 break;
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b8628a4..1a656ab 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -245,7 +245,15 @@
             int numDeferredJobs, long timeSinceLastJobRun);
 
     /**
-     * Report a sync that was scheduled by an active app is about to be executed.
+     * Report a sync is scheduled by a foreground app.
+     *
+     * @param packageName name of the package that owns the sync adapter.
+     * @param userId which user the app is associated with
+     */
+    public abstract void reportExemptedSyncScheduled(String packageName, @UserIdInt int userId);
+
+    /**
+     * Report a sync that was scheduled by a foreground app is about to be executed.
      *
      * @param packageName name of the package that owns the sync adapter.
      * @param userId which user the app is associated with
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f7908b6..32a6743 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -520,27 +520,36 @@
     public static final int SYNC_EXEMPTION_NONE = 0;
 
     /**
-     * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket
-     * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs.
+     * Exemption given to a sync request made by a foreground app (including
+     * PROCESS_STATE_IMPORTANT_FOREGROUND).
      *
-     * Note this will still *not* let RARE apps to run syncs, because they still won't get network
-     * connection.
+     * At the schedule time, we promote the sync adapter app for a higher bucket:
+     * - If the device is not dozing (so the sync will start right away)
+     *   promote to ACTIVE for 1 hour.
+     * - If the device is dozing (so the sync *won't* start right away),
+     * promote to WORKING_SET for 4 hours, so it'll get a higher chance to be started once the
+     * device comes out of doze.
+     * - When the sync actually starts, we promote the sync adapter app to ACTIVE for 10 minutes,
+     * so it can schedule and start more syncs without getting throttled, even when the first
+     * operation was canceled and now we're retrying.
+     *
+     *
      * @hide
      */
-    public static final int SYNC_EXEMPTION_ACTIVE = 1;
+    public static final int SYNC_EXEMPTION_PROMOTE_BUCKET = 1;
 
     /**
-     * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the
+     * In addition to {@link #SYNC_EXEMPTION_PROMOTE_BUCKET}, we put the sync adapter app in the
      * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
      * @hide
      */
-    public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2;
+    public static final int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP = 2;
 
     /** @hide */
     @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = {
             SYNC_EXEMPTION_NONE,
-            SYNC_EXEMPTION_ACTIVE,
-            SYNC_EXEMPTION_ACTIVE_WITH_TEMP,
+            SYNC_EXEMPTION_PROMOTE_BUCKET,
+            SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SyncExemption {}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 262de15..1275a85 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -813,6 +813,10 @@
     /**
      * <p>The camera device is a logical camera backed by two or more physical cameras that are
      * also exposed to the application.</p>
+     * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
+     * camera in the system. For an application that switches between front and back cameras,
+     * the recommendation is to switch between the first rear camera and the first front
+     * camera in the list of supported camera devices.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
      * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 105cd38..0257891 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -70,7 +70,7 @@
         assertNotCalled();
         mCalled = true;
         try {
-            mCallback.onFailure(message);
+            mCallback.onFailure(mRequestId, message);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 2bb3e9a..1bad1d7 100644
--- a/core/java/android/service/autofill/IFillCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -28,5 +28,5 @@
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
     void onSuccess(in FillResponse response);
-    void onFailure(CharSequence message);
+    void onFailure(int requestId, CharSequence message);
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4c7dc11..7555fff 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1899,10 +1899,20 @@
     }
 
     private LogMaker newLog(int category) {
-        return new LogMaker(category)
-                .setPackageName(mContext.getPackageName())
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE,
-                        isCompatibilityModeEnabledLocked() ? 1 : 0);
+        final LogMaker log = new LogMaker(category)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, mSessionId);
+
+        if (isCompatibilityModeEnabledLocked()) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+        }
+        final AutofillClient client = getClient();
+        if (client == null) {
+            // Client should never be null here, but it doesn't hurt to check...
+            log.setPackageName(mContext.getPackageName());
+        } else {
+            log.setComponentName(client.autofillClientGetComponentName());
+        }
+        return log;
     }
 
     /**
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index d22b1e6..6cb0eaa 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -285,10 +285,14 @@
         final Layout layout = mTextView.getLayout();
 
         final Runnable onAnimationEndCallback = () -> {
-            if (result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
+            final SelectionResult startSelectionResult;
+            if (result != null && result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
                     && result.mStart <= result.mEnd) {
-                startSelectionActionMode(result);
+                startSelectionResult = result;
+            } else {
+                startSelectionResult = null;
             }
+            startSelectionActionMode(startSelectionResult);
         };
         // TODO do not trigger the animation if the change included only non-printable characters
         final boolean didSelectionChange =
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index d468ce3..03a734d 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -82,7 +82,7 @@
     private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private Paint mTextPaint = new Paint();
     private CharSequence mConversationTitle;
-    private Icon mLargeIcon;
+    private Icon mAvatarReplacement;
     private boolean mIsOneToOne;
     private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
     private Person mUser;
@@ -125,8 +125,8 @@
     }
 
     @RemotableViewMethod
-    public void setLargeIcon(Icon icon) {
-        mLargeIcon = icon;
+    public void setAvatarReplacement(Icon icon) {
+        mAvatarReplacement = icon;
     }
 
     @RemotableViewMethod
@@ -228,7 +228,7 @@
             boolean isOwnMessage = group.getSender() == mUser;
             CharSequence senderName = group.getSenderName();
             if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)
-                    || (mIsOneToOne && mLargeIcon != null && !isOwnMessage)) {
+                    || (mIsOneToOne && mAvatarReplacement != null && !isOwnMessage)) {
                 continue;
             }
             String symbol = uniqueNames.get(senderName);
@@ -246,8 +246,8 @@
             if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
                 continue;
             }
-            if (mIsOneToOne && mLargeIcon != null && group.getSender() != mUser) {
-                group.setAvatar(mLargeIcon);
+            if (mIsOneToOne && mAvatarReplacement != null && group.getSender() != mUser) {
+                group.setAvatar(mAvatarReplacement);
             } else {
                 Icon cachedIcon = cachedAvatars.get(senderName);
                 if (cachedIcon == null) {
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 1113d6a..8c71b0b 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -25,7 +25,7 @@
 
 // Dump from com.android.server.ForceAppStandbyTracker.
 //
-// Next ID: 12
+// Next ID: 13
 message ForceAppStandbyTrackerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -41,6 +41,9 @@
     // App ids that are in power-save whitelist.
     repeated int32 power_save_whitelist_app_ids = 3;
 
+    // App ids that are in power-save user whitelist.
+    repeated int32 power_save_user_whitelist_app_ids = 12;
+
     // App ids that are in temporary power-save whitelist.
     repeated int32 temp_power_save_whitelist_app_ids = 4;
 
diff --git a/core/res/res/drawable/ic_arrow_forward.xml b/core/res/res/drawable/ic_arrow_forward.xml
new file mode 100644
index 0000000..f108570
--- /dev/null
+++ b/core/res/res/drawable/ic_arrow_forward.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.0,4.0l-1.41,1.41L16.17,11.0L4.0,11.0l0.0,2.0l12.17,0.0l-5.58,5.59L12.0,20.0l8.0,-8.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_permission.xml b/core/res/res/drawable/ic_permission.xml
new file mode 100644
index 0000000..0052350
--- /dev/null
+++ b/core/res/res/drawable/ic_permission.xml
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="16.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="
+        M9.0,12l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0z
+        m0.0,-4.0l-2.0,0.0l0.0,-4.0l2.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7708911..f7ff377 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3383,4 +3383,6 @@
 
   <java-symbol type="string" name="battery_saver_description_with_learn_more" />
   <java-symbol type="drawable" name="ic_lock_lockdown" />
+  <java-symbol type="drawable" name="ic_arrow_forward" />
+  <java-symbol type="drawable" name="ic_permission" />
 </resources>
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 3185ea2..e50a375 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
-    <application>
+    <application android:networkSecurityConfig="@xml/network_security_config">
         <uses-library android:name="android.test.runner" />
         <activity android:label="@string/app_name"
                 android:name="MediaFrameworkTest"
diff --git a/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c15c09c
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+    <base-config cleartextTrafficPermitted="true"/>
+</network-security-config>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 88edd12..7871020 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -211,6 +211,8 @@
     <!-- Permission necessary to change car audio volume through CarAudioManager -->
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
 
+    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..0899d35
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..2266449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..3328add
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..ed651da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..06e1202
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/car_add_circle_round.xml b/packages/SystemUI/res/drawable/car_add_circle_round.xml
index 5cf0c31..13c7dd1 100644
--- a/packages/SystemUI/res/drawable/car_add_circle_round.xml
+++ b/packages/SystemUI/res/drawable/car_add_circle_round.xml
@@ -1,4 +1,18 @@
 <?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.
+-->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
         <shape android:shape="oval">
diff --git a/packages/SystemUI/res/drawable/car_ic_add_white.xml b/packages/SystemUI/res/drawable/car_ic_add_white.xml
index f24771d..d681860 100644
--- a/packages/SystemUI/res/drawable/car_ic_add_white.xml
+++ b/packages/SystemUI/res/drawable/car_ic_add_white.xml
@@ -1,3 +1,17 @@
+<!-- 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.
+-->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="@dimen/car_touch_target_size"
     android:height="@dimen/car_touch_target_size"
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
index 907be01..2cd7883 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
@@ -21,10 +21,12 @@
                 android:height="21dp"
                 android:viewportWidth="24.0"
                 android:viewportHeight="24.0">
-            <group android:name="icon" android:pivotX="12" android:pivotY="12">
+            <!-- Use scaleX to flip icon so arrows always point in the direction of motion -->
+            <group android:name="icon" android:pivotX="12" android:pivotY="12"
+                   android:scaleX="?attr/rotateButtonScaleX">
                 <!-- Tint color to be set directly -->
                 <path android:fillColor="#FFFFFFFF"
-                      android:pathData="M12,4c-0.06,0 -0.12,0.01 -0.18,0.01l1.09,-1.09L11.5,1.5L8,5l3.5,3.5l1.41,-1.41l-1.08,-1.08C11.89,6.01 11.95,6 12,6c3.31,0 6,2.69 6,6c0,1.7 -0.71,3.23 -1.85,4.32l1.41,1.41C19.06,16.28 20,14.25 20,12C20,7.59 16.41,4 12,4zM16,19l-3.5,3.5l-1.41,-1.41l1.1,-1.1C12.13,19.98 12.06,20 12,20c-4.41,0 -8,-3.59 -8,-8c0,-2.25 0.94,-4.28 2.43,-5.73l1.41,1.41C6.71,8.77 6,10.3 6,12c0,3.31 2.69,6 6,6c0.05,0 0.11,-0.01 0.16,-0.01l-1.07,-1.07l1.41,-1.41L16,19z"/>
+                      android:pathData="M19,12c0,1.72 -0.63,3.3 -1.66,4.52l-1.44,-1.44C16.58,14.23 17,13.17 17,12c0,-2.76 -2.24,-5 -5,-5c-0.06,0 -0.11,0.01 -0.17,0.01l1.08,1.08L11.5,9.5L8,6l3.5,-3.5l1.41,1.42l-1.09,1.09C11.88,5.01 11.94,5 12,5C15.87,5 19,8.13 19,12zM12.5,14.51l-1.41,1.41l1.06,1.06C12.1,16.99 12.05,17 12,17c-2.76,0 -5,-2.24 -5,-5c0,-1.17 0.42,-2.23 1.09,-3.08L6.66,7.48C5.62,8.7 5,10.28 5,12c0,3.87 3.13,7 7,7c0.06,0 0.13,-0.01 0.19,-0.01v0l-1.1,1.1l1.41,1.41L16,18L12.5,14.51z"/>
             </group>
         </vector>
     </aapt:attr>
diff --git a/packages/SystemUI/res/layout/recents_onboarding.xml b/packages/SystemUI/res/layout/recents_onboarding.xml
index 093a7ce1..adf1e74 100644
--- a/packages/SystemUI/res/layout/recents_onboarding.xml
+++ b/packages/SystemUI/res/layout/recents_onboarding.xml
@@ -23,7 +23,7 @@
 
     <LinearLayout
         android:layout_width="wrap_content"
-        android:layout_height="40dp"
+        android:layout_height="wrap_content"
         android:paddingStart="24dp"
         android:paddingEnd="4dp"
         android:background="@drawable/recents_onboarding_toast_rounded_background"
@@ -33,8 +33,9 @@
 
         <TextView
             android:id="@+id/onboarding_text"
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:layout_gravity="center_vertical"
             android:textColor="@android:color/white"
             android:textSize="16sp"/>
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index 7931dfe..8b56b68 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -29,7 +29,6 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:gravity="center_vertical"
-        android:paddingStart="2dp"
         android:orientation="horizontal" >
 
         <FrameLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index c70e829..e67bb60 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -93,7 +93,7 @@
                     android:layout_gravity="center"
                     android:contentDescription="@string/accessibility_volume_settings"
                     android:background="@drawable/ripple_drawable_20dp"
-                    android:tint="?android:attr/textColorHint"
+                    android:tint="?android:attr/textColorSecondary"
                     android:soundEffectsEnabled="false" />
             </FrameLayout>
         </LinearLayout>
diff --git a/packages/SystemUI/res/values-ldrtl/strings.xml b/packages/SystemUI/res/values-ldrtl/strings.xml
new file mode 100644
index 0000000..c93da69
--- /dev/null
+++ b/packages/SystemUI/res/values-ldrtl/strings.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.
+ */
+-->
+<resources>
+    <!-- Recents: Text that shows above the navigation bar after launching several apps. [CHAR LIMIT=NONE] -->
+    <string name="recents_quick_scrub_onboarding">Drag left to quickly switch apps</string>
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 2ce9bfc..3f63f22 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -141,5 +141,7 @@
     <!-- Used to style rotate suggestion button AVD animations -->
     <attr name="rotateButtonStartAngle" format="float" />
     <attr name="rotateButtonEndAngle" format="float" />
+    <attr name="rotateButtonScaleX" format="float" />
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d8607cc..975055c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -125,9 +125,6 @@
     <color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
     <color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
 
-    <color name="volume_settings_icon_color">#7fffffff</color>
-    <color name="volume_slider_inactive">@*android:color/quaternary_device_default_settings</color>
-
     <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
@@ -141,7 +138,7 @@
     <color name="remote_input_accent">#eeeeee</color>
 
     <color name="quick_step_track_background_dark">#61000000</color>
-    <color name="quick_step_track_background_light">#4DFFFFFF</color>
+    <color name="quick_step_track_background_light">#33FFFFFF</color>
 
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/SystemUI/res/values/colors_car.xml
index cb3abb9..49bfb25 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/SystemUI/res/values/colors_car.xml
@@ -25,4 +25,7 @@
     <color name="car_user_switcher_name_text_color">@color/car_body1_light</color>
     <color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
     <color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
+
+    <!-- colors for volume dialog tint -->
+    <color name="car_volume_dialog_tint">@color/car_tint</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1aee7bc..89f9e1f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -939,7 +939,7 @@
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
     <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
-    <dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
+    <dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
 
     <!-- Navigation bar shadow params. -->
     <dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b3f4534..e4f5989 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -506,21 +506,25 @@
     <style name="RotateButtonCCWStart0">
         <item name="rotateButtonStartAngle">0</item>
         <item name="rotateButtonEndAngle">-90</item>
+        <item name="rotateButtonScaleX">1</item>
     </style>
 
     <style name="RotateButtonCCWStart90">
         <item name="rotateButtonStartAngle">90</item>
         <item name="rotateButtonEndAngle">0</item>
+        <item name="rotateButtonScaleX">1</item>
     </style>
 
     <style name="RotateButtonCWStart0">
         <item name="rotateButtonStartAngle">0</item>
         <item name="rotateButtonEndAngle">90</item>
+        <item name="rotateButtonScaleX">-1</item>
     </style>
 
     <style name="RotateButtonCWStart90">
         <item name="rotateButtonStartAngle">90</item>
         <item name="rotateButtonEndAngle">180</item>
+        <item name="rotateButtonScaleX">-1</item>
     </style>
 
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 52e1c16..24875d7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -58,7 +58,7 @@
 
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
-import androidx.slice.SliceManager;
+import androidx.slice.SliceViewManager;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.widget.ListContent;
 import androidx.slice.widget.RowContent;
@@ -373,7 +373,7 @@
     }
 
     public void refresh() {
-        Slice slice = SliceManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
+        Slice slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
         onChanged(slice);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 56cb888..19f8416 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui;
 
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.slice.SliceManager;
@@ -61,7 +63,9 @@
                     .setNegativeButton(R.string.slice_permission_deny, this)
                     .setPositiveButton(R.string.slice_permission_allow, this)
                     .setOnDismissListener(this)
-                    .show();
+                    .create();
+            dialog.getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+            dialog.show();
             TextView t1 = dialog.getWindow().getDecorView().findViewById(R.id.text1);
             t1.setText(getString(R.string.slice_permission_text_1, app2));
             TextView t2 = dialog.getWindow().getDecorView().findViewById(R.id.text2);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index fec76f2..086c87b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -173,7 +173,7 @@
                                             : SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS_BACK_OFF;
                             mNumAppsLaunchedSinceSwipeUpTipDismiss++;
                             if (mNumAppsLaunchedSinceSwipeUpTipDismiss
-                                    == swipeUpShowOnAppLauncherAfterDismiss) {
+                                    >= swipeUpShowOnAppLauncherAfterDismiss) {
                                 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
                                 shouldLog = show(R.string.recents_swipe_up_onboarding);
                             }
@@ -188,7 +188,7 @@
                     if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                         if (mHasDismissedQuickScrubTip) {
                             if (mOverviewOpenedCountSinceQuickScrubTipDismiss
-                                    == QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+                                    >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                                 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
                                 shouldLog = show(R.string.recents_quick_scrub_onboarding);
                             }
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 68359bf..9acac22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1144,6 +1144,8 @@
             mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
             mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
             mRoot.postOnAnimationDelayed(mRipple, 2*RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 3*RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 4*RIPPLE_INTERVAL_MS);
         }
 
         public void stop() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index b55fe47..860b77e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -29,14 +29,13 @@
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.FloatProperty;
@@ -55,6 +54,7 @@
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.system.NavigationBarCompat;
+import com.android.internal.graphics.ColorUtils;
 
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub.
@@ -63,7 +63,8 @@
 
     private static final String TAG = "QuickStepController";
     private static final int ANIM_IN_DURATION_MS = 150;
-    private static final int ANIM_OUT_DURATION_MS = 100;
+    private static final int ANIM_OUT_DURATION_MS = 134;
+    private static final float TRACK_SCALE = 0.95f;
 
     private NavigationBarView mNavigationBarView;
 
@@ -76,6 +77,7 @@
     private boolean mIsVertical;
     private boolean mIsRTL;
     private float mTrackAlpha;
+    private float mTrackScale = TRACK_SCALE;
     private int mLightTrackColor;
     private int mDarkTrackColor;
     private float mDarkIntensity;
@@ -85,7 +87,7 @@
 
     private final Handler mHandler = new Handler();
     private final Rect mTrackRect = new Rect();
-    private final Paint mTrackPaint = new Paint();
+    private final Drawable mTrackDrawable;
     private final OverviewProxyService mOverviewEventSender;
     private final int mTrackThickness;
     private final int mTrackEndPadding;
@@ -108,6 +110,20 @@
         }
     };
 
+    private final FloatProperty<QuickStepController> mTrackScaleProperty =
+            new FloatProperty<QuickStepController>("TrackScale") {
+        @Override
+        public void setValue(QuickStepController controller, float scale) {
+            mTrackScale = scale;
+            mNavigationBarView.invalidate();
+        }
+
+        @Override
+        public Float get(QuickStepController controller) {
+            return mTrackScale;
+        }
+    };
+
     private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
             new FloatProperty<QuickStepController>("NavBarAlpha") {
         @Override
@@ -139,7 +155,7 @@
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
         mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
         mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
-        mTrackPaint.setAlpha(0);
+        mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
     }
 
     public void setComponents(NavigationBarView navigationBarView) {
@@ -296,9 +312,17 @@
         }
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
                 mDarkTrackColor);
-        mTrackPaint.setColor(color);
-        mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
-        canvas.drawRect(mTrackRect, mTrackPaint);
+        int colorAlpha = ColorUtils.setAlphaComponent(color,
+                (int) (Color.alpha(color) * mTrackAlpha));
+        mTrackDrawable.setTint(colorAlpha);
+
+        // Scale the track, but apply the inverse scale from the nav bar
+        canvas.save();
+        canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
+                1f / mNavigationBarView.getScaleY(),
+                mTrackRect.centerX(), mTrackRect.centerY());
+        mTrackDrawable.draw(canvas);
+        canvas.restore();
     }
 
     @Override
@@ -322,6 +346,7 @@
             x2 = x1 + width - 2 * mTrackEndPadding;
         }
         mTrackRect.set(x1, y1, x2, y2);
+        mTrackDrawable.setBounds(mTrackRect);
     }
 
     @Override
@@ -387,7 +412,9 @@
             mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
             mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
 
-            ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 1f);
+            ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
+                    PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
+                    PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
             trackAnimator.setInterpolator(ALPHA_IN);
             trackAnimator.setDuration(ANIM_IN_DURATION_MS);
             ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
@@ -438,7 +465,9 @@
             mTrackAnimator.cancel();
         }
 
-        ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 0f);
+        ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
+                PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
+                PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
         trackAnimator.setInterpolator(ALPHA_OUT);
         trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
         ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 7cd433a..384a6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -148,16 +148,31 @@
         boolean in = activityIn && mActivityEnabled && visible;
         boolean out = activityOut && mActivityEnabled && visible;
 
-        mWifiIconState.visible = visible;
-        mWifiIconState.resId = statusIcon.icon;
-        mWifiIconState.activityIn = in;
-        mWifiIconState.activityOut = out;
-        mWifiIconState.slot = mSlotWifi;
-        mWifiIconState.airplaneSpacerVisible = mIsAirplaneMode;
-        mWifiIconState.contentDescription = statusIcon.contentDescription;
+        WifiIconState newState = mWifiIconState.copy();
 
-        if (mWifiIconState.visible && mWifiIconState.resId > 0) {
-            mIconController.setSignalIcon(mSlotWifi, mWifiIconState.copy());
+        newState.visible = visible;
+        newState.resId = statusIcon.icon;
+        newState.activityIn = in;
+        newState.activityOut = out;
+        newState.slot = mSlotWifi;
+        newState.airplaneSpacerVisible = mIsAirplaneMode;
+        newState.contentDescription = statusIcon.contentDescription;
+
+        MobileIconState first = getFirstMobileState();
+        newState.signalSpacerVisible = first != null && first.typeId != 0;
+
+        updateWifiIconWithState(newState);
+        mWifiIconState = newState;
+    }
+
+    private void updateShowWifiSignalSpacer(WifiIconState state) {
+        MobileIconState first = getFirstMobileState();
+        state.signalSpacerVisible = first != null && first.typeId != 0;
+    }
+
+    private void updateWifiIconWithState(WifiIconState state) {
+        if (state.visible && state.resId > 0) {
+            mIconController.setSignalIcon(mSlotWifi, state);
             mIconController.setIconVisibility(mSlotWifi, true);
         } else {
             mIconController.setIconVisibility(mSlotWifi, false);
@@ -173,6 +188,9 @@
             return;
         }
 
+        // Visibility of the data type indicator changed
+        boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
+
         state.visible = statusIcon.visible && !mBlockMobile;
         state.strengthId = statusIcon.icon;
         state.typeId = statusType;
@@ -184,6 +202,15 @@
 
         // Always send a copy to maintain value type semantics
         mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
+
+        if (typeChanged) {
+            WifiIconState wifiCopy = mWifiIconState.copy();
+            updateShowWifiSignalSpacer(wifiCopy);
+            if (!Objects.equals(wifiCopy, mWifiIconState)) {
+                updateWifiIconWithState(wifiCopy);
+                mWifiIconState = wifiCopy;
+            }
+        }
     }
 
     private MobileIconState getState(int subId) {
@@ -196,6 +223,14 @@
         return null;
     }
 
+    private MobileIconState getFirstMobileState() {
+        if (mMobileStates.size() > 0) {
+            return mMobileStates.get(0);
+        }
+
+        return null;
+    }
+
 
     /**
      * It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 4ec9ae8..b814478 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -565,10 +565,12 @@
 
         @Override
         public boolean onKeyPreIme(int keyCode, KeyEvent event) {
-            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-                mRemoteInputView.mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
+            // When BACK key is pressed, this method would be invoked twice.
+            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
+                    event.getAction() == KeyEvent.ACTION_UP) {
+                defocusIfNeeded(true /* animate */);
             }
-            return super.dispatchKeyEvent(event);
+            return super.onKeyPreIme(keyCode, event);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 8034345..bf962b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -344,13 +344,17 @@
       int supplementalIconId, @Nullable View.OnClickListener supplementalIconOnClickListener) {
     SeekbarListItem listItem = new SeekbarListItem(mContext);
     listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
+    int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
     int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
     listItem.setProgress(progress);
     listItem.setOnSeekBarChangeListener(
         new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
-    listItem.setPrimaryActionIcon(mContext.getResources().getDrawable(volumeItem.icon));
+    Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+    primaryIcon.setTint(color);
+    listItem.setPrimaryActionIcon(primaryIcon);
     if (supplementalIconId != 0) {
       Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
+      supplementalIcon.setTint(color);
       listItem.setSupplementalIcon(supplementalIcon, true,
           supplementalIconOnClickListener);
     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 03474a8..ed243ef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -43,8 +43,10 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -90,6 +92,7 @@
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.VolumeDialogController.State;
 import com.android.systemui.plugins.VolumeDialogController.StreamState;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
@@ -131,8 +134,10 @@
     private final AccessibilityManagerWrapper mAccessibilityMgr;
     private final Object mSafetyWarningLock = new Object();
     private final Accessibility mAccessibility = new Accessibility();
-    private final ColorStateList mActiveTint;
-    private final ColorStateList mInactiveTint;
+    private ColorStateList mActiveTint;
+    private int mActiveAlpha;
+    private ColorStateList mInactiveTint;
+    private int mInactiveAlpha;
 
     private boolean mShowing;
     private boolean mShowA11yStream;
@@ -150,8 +155,6 @@
         mController = Dependency.get(VolumeDialogController.class);
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
-        mActiveTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
-        mInactiveTint = loadColorStateList(R.color.volume_slider_inactive);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
     }
 
@@ -224,6 +227,12 @@
             return true;
         });
 
+        mActiveTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
+        mActiveAlpha = Color.alpha(mActiveTint.getDefaultColor());
+        mInactiveTint = ColorStateList.valueOf(
+                Utils.getColorAttr(mContext, android.R.attr.colorForeground));
+        mInactiveAlpha = getAlphaAttr(android.R.attr.secondaryContentAlpha);
+
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         mRinger = mDialog.findViewById(R.id.ringer);
         mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
@@ -263,8 +272,11 @@
         return mDialogView;
     }
 
-    private ColorStateList loadColorStateList(int colorResId) {
-        return ColorStateList.valueOf(mContext.getColor(colorResId));
+    private int getAlphaAttr(int attr) {
+        TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr});
+        float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        return (int) (alpha * 255);
     }
 
     private boolean isLandscape() {
@@ -890,12 +902,16 @@
         if (isActive) {
             row.slider.requestFocus();
         }
-        final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveTint
-                : mInactiveTint;
+        boolean useActiveColoring = isActive && row.slider.isEnabled();
+        final ColorStateList tint = useActiveColoring ? mActiveTint : mInactiveTint;
+        final int alpha = useActiveColoring ? mActiveAlpha : mInactiveAlpha;
         if (tint == row.cachedTint) return;
         row.slider.setProgressTintList(tint);
         row.slider.setThumbTintList(tint);
+        row.slider.setProgressBackgroundTintList(tint);
+        row.slider.setAlpha(((float) alpha) / 255);
         row.icon.setImageTintList(tint);
+        row.icon.setImageAlpha(alpha);
         row.cachedTint = tint;
     }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d064105..4328d94 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3986,27 +3986,44 @@
     // OS: O
     APP_TRANSITION_IS_EPHEMERAL = 905;
 
-    // An autofill session was started
+    // An autofill session was started.
+    // OS: O
     // Package: Package of app that is autofilled
     // NOTE: starting on OS MR1, it also added the following field:
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // NOTE: starting on OS P, it also added the following field:
-    // Tag FIELD_FLAGS - Flags used to start the session
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFIL_FLAGS: flags used to start the session.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session started.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SESSION_STARTED = 906;
 
     // An autofill request was processed by a service
-    // Type TYPE_SUCCESS: The request succeeded
-    // Type TYPE_FAILURE: The request failed
+    // Type TYPE_SUCCESS: service called FillCalback.onSuccess()
+    // Type TYPE_FAILURE: service called FillCallback.onFailure()
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned in the response, or -1 if
-    // the service returned a null response.
-    // NOTE: starting on OS P, it also added:
-    // Type TYPE_CLOSE: Service returned a null response.
+    // the service returned a null response
+    // NOTE: starting on OS P, it also added the following fields:
+    // TYPE_CLOSE: request timed out before service called a FillCallback method
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_REQUEST_ORDINAL: sequence number of the request inside a session; starts
+    //     with 1.
+    // Tag FIELD_AUTOFILL_FLAGS: flags used to request autofill
+    // Tag FIELD_AUTOFILL_DURATION: how long it took (in ms) to show the autofill UI after a field
+    //     was focused.
+    // Tag FIELD_AUTOFILL_AUTHENTICATION_STATUS: status of authenticated datasets or responses.
     // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
-    // number of entries field ids in the request.
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    //     number of entries field ids in the request.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: Prior to P, some of the fields above were logged by 5 different metrics:
+    // - AUTOFILL_UI_LATENCY
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -4023,9 +4040,11 @@
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
-    // NOTE: starting on OS P, it also added the following field:
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FILL_UI = 910;
 
     // Tag of a field for the length of the filter text
@@ -4034,16 +4053,17 @@
     // An autofill authentication succeeded
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_AUTHENTICATED = 912;
 
     // An activity was autofilled and all values could be applied
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
     // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATASET_APPLIED = 913;
 
     // Tag of a field for the number values to be filled in
@@ -4058,28 +4078,37 @@
     // Type TYPE_ACTION: data was saved
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved
-    // NOTE: starting on OS P, it also added the following field:
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_UI = 916;
 
     // Tag of a field for the number of saveable ids
     FIELD_AUTOFILL_NUM_IDS = 917;
 
-    // ACTION: An autofill service was reqiested to save data
+    // ACTION: An autofill service was requested to save data
     // Type TYPE_SUCCESS: The request succeeded right away
     // Type TYPE_OPEN: The request succeeded but the service launched an IntentSender
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATA_SAVE_REQUEST = 918;
 
     // An auto-fill session was finished
+    // OS: O
     // Package: Package of app that was autofilled
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_NUMBER_REQUESTS: number of requests made to the service (each request
+    //     is logged by a separate AUTOFILL_REQUEST metric)
     AUTOFILL_SESSION_FINISHED = 919;
 
     // meta-event: a reader has checkpointed the log here.
@@ -4206,7 +4235,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
     // TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
 
     // FIELD - The component that an app tried tro forged.
@@ -4664,8 +4693,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_VALUE_RESET = 1124;
 
     // Tag of AUTOFILL_VALUE_RESET
@@ -4675,25 +4706,21 @@
     // An autofill dataset authentication succeeded
     // Package: Package of app that was autofilled
     // OS: O MR
-    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_DATASET_AUTHENTICATED = 1126;
 
     // An autofill service provided an invalid dataset authentication
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
 
     // An autofill service provided an invalid authentication extra
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_AUTHENTICATION = 1128;
 
     // An autofill service used a custom description (using RemoteViews) in the autofill save UI
@@ -4701,8 +4728,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129;
 
     // FIELD - Type of save object passed by the service when the Save UI is shown
@@ -4714,8 +4743,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131;
 
     // User tapped a link in the custom description of the autofill save UI provided by an autofill service
@@ -4726,8 +4757,10 @@
     // Type TYPE_FAILURE: The link could not launc an activity
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_LINK_TAPPED = 1132;
 
     // Result of the validation on save when an autofill service provided a validator
@@ -4738,8 +4771,10 @@
     // Type TYPE_DISMISS: The validation failed
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_VALIDATION = 1133;
 
     // Result of an operation in the autofill save UI after the user tapped a link in the custom description
@@ -4749,8 +4784,10 @@
     // Type TYPE_OPEN: The autofill save UI was restored
     // Type TYPE_DISMISS: The autofill save UI was destroyed
     // Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
 
     // Autofill service called API that disables itself
@@ -4758,13 +4795,12 @@
     // OS: O MR
     AUTOFILL_SERVICE_DISABLED_SELF = 1135;
 
+    // DEPRECATED - on P it was merged with AUTOFILL_REQUEST
     // Reports how long it took to show the autofill UI after a field was focused
     // Tag FIELD_AUTOFILL_DURATION: Duration in ms
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Package: Package of the autofill service
     // OS: O MR
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_UI_LATENCY = 1136;
 
     // Action: the snooze leave-behind was shown after the user clicked the snooze icon
@@ -4931,15 +4967,19 @@
     // An autofill service explicitly defined which view should commit the autofill context
     // Package: Package of app that is autofilled
     // OS: P
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION = 1228;
 
     // The autofill context was commited when the user clicked a view explicitly marked by the
     // service as committing it
     // Package: Package of app that is autofilled
     // OS: P
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_EXPLICITLY_TRIGGERED = 1229;
 
     // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
@@ -4952,7 +4992,8 @@
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_APP = 1231;
 
     // An autofill service asked to disable autofill for a given activity.
@@ -4961,7 +5002,8 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_CLASS_NAME: Class name of the activity that is being disabled for autofill
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_ACTIVITY = 1232;
 
     // ACTION: Stop an app and turn on background check
@@ -5171,9 +5213,11 @@
     // Package: Package of app that is autofilled
     // Counter: number of matches found
     // OS: P
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_MATCH_SCORE: Average score of the matches, in the range of 0 to 100
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
 
     // Tag used to report autofill field classification scores
@@ -5840,6 +5884,7 @@
     ACTION_STORAGE_MIGRATE_LATER = 1413;
 
     // Tag used to report whether an activity is being autofilled  on compatibility mode.
+    // OS: P
     FIELD_AUTOFILL_COMPAT_MODE = 1414;
 
     // OPEN: Settings > Sound > Switch a2dp devices dialog
@@ -6045,6 +6090,32 @@
     // OS: P
     ACTION_BATTERY_CAUSED_SHUTDOWN = 1451;
 
+    // FIELD: Flags used on autofill-related metrics
+    // OS: P
+    FIELD_AUTOFILL_FLAGS = 1452;
+
+    // Tag used when the service returned an authenticated dataset or response.
+    // Used to replace the following individual metrics, which now are logged as the value of this
+    // field in the AUTOFILL_REQUEST metric:
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
+    // OS: P
+    FIELD_AUTOFILL_AUTHENTICATION_STATUS = 1453;
+
+    // FIELD: Index of the autofill request inside of a session.
+    // OS: P
+    FIELD_AUTOFILL_REQUEST_ORDINAL = 1454;
+
+    // FIELD: Number of requests made to an autofill service during a session.
+    // OS: P
+    FIELD_AUTOFILL_NUMBER_REQUESTS = 1455;
+
+    // FIELD: Id of the autofill session associated with this metric.
+    // OS: P
+    FIELD_AUTOFILL_SESSION_ID = 1456;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d97253e..1ccce17 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -537,11 +537,17 @@
             final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
             Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
                     + ") passed component (" + componentName + ") owned by UID " + packageUid);
-            mMetricsLogger.write(
-                    Helper.newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT,
-                            callingPackage, getServicePackageName(), compatMode)
+
+            // NOTE: not using Helper.newLogMaker() because we don't have the session id
+            final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
+                    .setPackageName(callingPackage)
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
-                            componentName == null ? "null" : componentName.flattenToShortString()));
+                            componentName == null ? "null" : componentName.flattenToShortString());
+            if (compatMode) {
+                log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+            }
+            mMetricsLogger.write(log);
 
             throw new SecurityException("Invalid component: " + componentName);
         }
@@ -780,10 +786,10 @@
             @Nullable ArrayList<String> changedDatasetIds,
             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @NonNull String appPackageName, boolean compatMode) {
+            @NonNull ComponentName appComponentName, boolean compatMode) {
         logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
                 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
-                manuallyFilledDatasetIds, null, null, appPackageName, compatMode);
+                manuallyFilledDatasetIds, null, null, appComponentName, compatMode);
     }
 
     @GuardedBy("mLock")
@@ -796,7 +802,7 @@
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
             @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
-            @NonNull String appPackageName, boolean compatMode) {
+            @NonNull ComponentName appComponentName, boolean compatMode) {
         if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
             if (sVerbose) {
                 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
@@ -807,6 +813,7 @@
                         + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
                         + ", detectedFieldIds=" + detectedFieldIdsList
                         + ", detectedFieldClassifications=" + detectedFieldClassificationsList
+                        + ", appComponentName=" + appComponentName.toShortString()
                         + ", compatMode=" + compatMode);
             }
             AutofillId[] detectedFieldsIds = null;
@@ -834,7 +841,7 @@
                 final int averageScore = (int) ((totalScore * 100) / totalSize);
                 mMetricsLogger.write(Helper
                         .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
-                                appPackageName, getServicePackageName(), compatMode)
+                                appComponentName, getServicePackageName(), sessionId, compatMode)
                         .setCounterValue(numberFields)
                         .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
                                 averageScore));
@@ -889,9 +896,11 @@
             }
             mUserData = userData;
             // Log it
-            int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
-            mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
-                    getServicePackageName(), null)
+            final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
+            // NOTE: contrary to most metrics, the service name is logged as the main package name
+            // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE
+            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED)
+                    .setPackageName(getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
         }
     }
@@ -1130,7 +1139,8 @@
     /**
      * Called by {@link Session} when service asked to disable autofill for an app.
      */
-    void disableAutofillForApp(@NonNull String packageName, long duration, boolean compatMode) {
+    void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
+            boolean compatMode) {
         synchronized (mLock) {
             if (mDisabledApps == null) {
                 mDisabledApps = new ArrayMap<>(1);
@@ -1143,7 +1153,7 @@
             mDisabledApps.put(packageName, expiration);
             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
-                    packageName, getServicePackageName(), compatMode)
+                    packageName, getServicePackageName(), sessionId, compatMode)
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
         }
     }
@@ -1152,7 +1162,7 @@
      * Called by {@link Session} when service asked to disable autofill an app.
      */
     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
-            boolean compatMode) {
+            int sessionId, boolean compatMode) {
         synchronized (mLock) {
             if (mDisabledActivities == null) {
                 mDisabledActivities = new ArrayMap<>(1);
@@ -1163,14 +1173,20 @@
                 expiration = Long.MAX_VALUE;
             }
             mDisabledActivities.put(componentName, expiration);
-            final int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
+            final int intDuration = duration > Integer.MAX_VALUE
+                    ? Integer.MAX_VALUE
+                    : (int) duration;
             // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead
             // of package name
-            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
+            final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
                     .setComponentName(componentName)
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration)
-                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0));
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
+            if (compatMode) {
+                log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+            }
+            mMetricsLogger.write(log);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index f781013..cf310e9 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
+import android.content.ComponentName;
 import android.metrics.LogMaker;
 import android.service.autofill.Dataset;
 import android.util.ArrayMap;
@@ -109,20 +110,29 @@
     }
 
     @NonNull
-    public static LogMaker newLogMaker(int category, String packageName,
-            String servicePackageName) {
-        final LogMaker log = new LogMaker(category).setPackageName(packageName);
-        if (servicePackageName != null) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
+    private static LogMaker newLogMaker(int category, @NonNull String servicePackageName,
+            int sessionId, boolean compatMode) {
+        final LogMaker log = new LogMaker(category)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
+        if (compatMode) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
         }
         return log;
     }
 
     @NonNull
-    public static LogMaker newLogMaker(int category, String packageName,
-            String servicePackageName, boolean compatMode) {
-        return newLogMaker(category, packageName, servicePackageName)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0);
+    public static LogMaker newLogMaker(int category, @NonNull String packageName,
+            @NonNull String servicePackageName, int sessionId, boolean compatMode) {
+        return newLogMaker(category, servicePackageName, sessionId, compatMode)
+                .setPackageName(packageName);
+    }
+
+    @NonNull
+    public static LogMaker newLogMaker(int category, @NonNull ComponentName componentName,
+            @NonNull String servicePackageName, int sessionId, boolean compatMode) {
+        return newLogMaker(category, servicePackageName, sessionId, compatMode)
+                .setComponentName(componentName);
     }
 
     public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
@@ -193,6 +203,18 @@
         return urlBarNode;
     }
 
+    /**
+     * Gets the value of a metric tag, or {@code 0} if not found or NaN.
+     */
+    static int getNumericValue(@NonNull LogMaker log, int tag) {
+        final Object value = log.getTaggedData(tag);
+        if (!(value instanceof Number)) {
+            return 0;
+        } else {
+            return ((Number) value).intValue();
+        }
+    }
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 4ded3fe..3e932e8 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -99,12 +99,14 @@
     private PendingRequest mPendingRequest;
 
     public interface FillServiceCallbacks {
-        void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
+        void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+                @NonNull String servicePackageName, int requestFlags);
+        void onFillRequestFailure(int requestId, @Nullable CharSequence message,
                 @NonNull String servicePackageName);
-        void onFillRequestFailure(@Nullable CharSequence message,
-                @NonNull String servicePackageName);
+        void onFillRequestTimeout(int requestId, @NonNull String servicePackageName);
         void onSaveRequestSuccess(@NonNull String servicePackageName,
                 @Nullable IntentSender intentSender);
+        // TODO(b/80093094): add timeout here too?
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
         void onServiceDied(RemoteFillService service);
@@ -301,21 +303,31 @@
         mContext.unbindService(mServiceConnection);
     }
 
-    private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, int requestFlags,
-            FillResponse response) {
+    private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
+            @Nullable FillResponse response, int requestFlags) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestSuccess(requestFlags, response,
+                mCallbacks.onFillRequestSuccess(pendingRequest.mRequest.getId(), response,
+                        mComponentName.getPackageName(), requestFlags);
+            }
+        });
+    }
+
+    private void dispatchOnFillRequestFailure(@NonNull PendingFillRequest pendingRequest,
+            @Nullable CharSequence message) {
+        mHandler.post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onFillRequestFailure(pendingRequest.mRequest.getId(), message,
                         mComponentName.getPackageName());
             }
         });
     }
 
-    private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
-            @Nullable CharSequence message) {
+    private void dispatchOnFillRequestTimeout(@NonNull PendingFillRequest pendingRequest) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
+                mCallbacks.onFillRequestTimeout(pendingRequest.mRequest.getId(),
+                        mComponentName.getPackageName());
             }
         });
     }
@@ -538,18 +550,18 @@
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
-                                request.getFlags(), response);
+                                response, request.getFlags());
                     }
                 }
 
                 @Override
-                public void onFailure(CharSequence message) {
+                public void onFailure(int requestId, CharSequence message) {
                     if (!finish()) return;
 
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        remoteService.dispatchOnFillRequestFailure(
-                                PendingFillRequest.this, message);
+                        remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this,
+                                message);
                     }
                 }
             };
@@ -566,7 +578,7 @@
             if (cancellation != null) {
                 remoteService.dispatchOnFillTimeout(cancellation);
             }
-            remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
+            remoteService.dispatchOnFillRequestTimeout(PendingFillRequest.this);
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 73c7172..fbbb76c 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -27,6 +27,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.autofill.Helper.getNumericValue;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
@@ -93,6 +94,7 @@
 import com.android.server.autofill.ui.PendingUi;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -176,7 +178,7 @@
 
     /**
      * Contexts read from the app; they will be updated (sanitized, change values for save) before
-     * sent to {@link AutofillService}. Ordered by the time they we read.
+     * sent to {@link AutofillService}. Ordered by the time they were read.
      */
     @GuardedBy("mLock")
     private ArrayList<FillContext> mContexts;
@@ -231,6 +233,12 @@
     private final LocalLog mWtfHistory;
 
     /**
+     * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
@@ -483,8 +491,18 @@
             requestId = sIdCounter.getAndIncrement();
         } while (requestId == INVALID_REQUEST_ID);
 
+        // Create a metrics log for the request
+        final int ordinal = mRequestLogs.size() + 1;
+        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
+        if (flags != 0) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags);
+        }
+        mRequestLogs.put(requestId, log);
+
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for requestId=" + requestId + ", flags=" + flags);
+            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId="
+                    + requestId + ", flags=" + flags);
         }
 
         // If the focus changes very quickly before the first request is returned each focus change
@@ -537,7 +555,7 @@
         setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
-                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
     }
 
     /**
@@ -604,21 +622,30 @@
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
-            @NonNull String servicePackageName) {
+    public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+            @NonNull String servicePackageName, int requestFlags) {
         final AutofillId[] fieldClassificationIds;
 
+        final LogMaker requestLog;
+
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
                         + id + " destroyed");
                 return;
             }
+
+            requestLog = mRequestLogs.get(requestId);
+            if (requestLog != null) {
+                requestLog.setType(MetricsEvent.TYPE_SUCCESS);
+            } else {
+                Slog.w(TAG, "onFillRequestSuccess(): no request log for id " + requestId);
+            }
             if (response == null) {
+                if (requestLog != null) {
+                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
+                }
                 processNullResponseLocked(requestFlags);
-                mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                        .setType(MetricsEvent.TYPE_SUCCESS)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1));
                 return;
             }
 
@@ -645,10 +672,11 @@
                 Slog.d(TAG, message.toString());
             }
             if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) {
-                mService.disableAutofillForActivity(mComponentName, disableDuration, mCompatMode);
+                mService.disableAutofillForActivity(mComponentName, disableDuration,
+                        id, mCompatMode);
             } else {
                 mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
-                        mCompatMode);
+                        id, mCompatMode);
             }
             sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
         }
@@ -659,38 +687,54 @@
             // Response is "empty" from an UI point of view, need to notify client.
             notifyUnavailableToClient(sessionFinishedState);
         }
+
+        if (requestLog != null) {
+            requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                            response.getDatasets() == null ? 0 : response.getDatasets().size());
+            if (fieldClassificationIds != null) {
+                requestLog.addTaggedData(
+                        MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
+                        fieldClassificationIds.length);
+            }
+        }
+
         synchronized (mLock) {
             processResponseLocked(response, null, requestFlags);
         }
-
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_SUCCESS)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
-                        response.getDatasets() == null ? 0 : response.getDatasets().size());
-        if (fieldClassificationIds != null) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
-                    fieldClassificationIds.length);
-        }
-        mMetricsLogger.write(log);
     }
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestFailure(@Nullable CharSequence message,
+    public void onFillRequestFailure(int requestId, @Nullable CharSequence message,
             @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, false, message, servicePackageName);
+    }
+
+    // FillServiceCallbacks
+    @Override
+    public void onFillRequestTimeout(int requestId, @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, true, null, servicePackageName);
+    }
+
+    private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut,
+            @Nullable CharSequence message, @NonNull String servicePackageName) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestFailure() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
+                        + ") rejected - session: " + id + " destroyed");
                 return;
             }
             mService.resetLastResponse();
+            final LogMaker requestLog = mRequestLogs.get(requestId);
+            if (requestLog == null) {
+                Slog.w(TAG, "onFillRequestFailureOrTimeout(): no log for id " + requestId);
+            } else {
+                requestLog.setType(timedOut ? MetricsEvent.TYPE_CLOSE : MetricsEvent.TYPE_FAILURE);
+            }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_FAILURE);
-        mMetricsLogger.write(log);
-
-        getUiForShowing().showError(message, this);
+        if (message != null) {
+            getUiForShowing().showError(message, this);
+        }
         removeSelf();
     }
 
@@ -973,11 +1017,12 @@
                     + ", clientState=" + newClientState);
         }
         if (result instanceof FillResponse) {
-            writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED);
+            logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
         } else if (result instanceof Dataset) {
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-                writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
                 if (newClientState != null) {
                     if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                     mClientState = newClientState;
@@ -986,13 +1031,15 @@
                 authenticatedResponse.getDatasets().set(datasetIdx, dataset);
                 autoFill(requestId, datasetIdx, dataset, false);
             } else {
-                writeLog(MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
             }
         } else {
             if (result != null) {
                 Slog.w(TAG, "service returned invalid auth type: " + result);
             }
-            writeLog(MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+            logAuthenticationStatusLocked(requestId,
+                    MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
             processNullResponseLocked(0);
         }
     }
@@ -1253,7 +1300,7 @@
             mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                     ignoredDatasets, changedFieldIds, changedDatasetIds,
                     manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    mComponentName.getPackageName(), mCompatMode);
+                    mComponentName, mCompatMode);
         }
     }
 
@@ -1308,7 +1355,7 @@
                 mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                         ignoredDatasets, changedFieldIds, changedDatasetIds,
                         manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                        mComponentName.getPackageName(), mCompatMode);
+                        mComponentName, mCompatMode);
                 return;
             }
             final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -1373,7 +1420,7 @@
             mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                     ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
                     manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                    mComponentName.getPackageName(), mCompatMode);
+                    mComponentName, mCompatMode);
         });
 
         fcStrategy.getScores(callback, algorithm, algorithmArgs, currentValues, userValues);
@@ -1404,7 +1451,7 @@
          *   the current values of all fields in the screen.
          */
         if (saveInfo == null) {
-            if (sVerbose) Slog.w(TAG, "showSaveLocked(): no saveInfo from service");
+            if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service");
             return true;
         }
 
@@ -1603,8 +1650,7 @@
                 mPendingSaveUi = new PendingUi(mActivityToken, id, client);
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
                         mService.getServicePackageName(), saveInfo, this,
-                        mComponentName.getPackageName(), this,
-                        mPendingSaveUi, mCompatMode);
+                        mComponentName, this, mPendingSaveUi, mCompatMode);
                 if (client != null) {
                     try {
                         client.setSaveUiState(id, true);
@@ -2065,7 +2111,7 @@
     }
 
     @Override
-    public void onFillReady(FillResponse response, AutofillId filledId,
+    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
             @Nullable AutofillValue value) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2081,8 +2127,8 @@
         }
 
         getUiForShowing().showFillUi(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName.getPackageName(),
-                mService.getServiceLabel(), mService.getServiceIcon(), this, mCompatMode);
+                mService.getServicePackageName(), mComponentName,
+                mService.getServiceLabel(), mService.getServiceIcon(), this, id, mCompatMode);
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -2103,9 +2149,8 @@
                 TimeUtils.formatDuration(duration, historyLog);
                 mUiLatencyHistory.log(historyLog.toString());
 
-                final LogMaker metricsLog = newLogMaker(MetricsEvent.AUTOFILL_UI_LATENCY)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
-                mMetricsLogger.write(metricsLog);
+                addTaggedDataToRequestLogLocked(response.getRequestId(),
+                        MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
             }
         }
     }
@@ -2474,6 +2519,14 @@
             TimeUtils.formatDuration(mUiShownTime - mStartTime, pw);
             pw.println();
         }
+        final int requestLogsSizes = mRequestLogs.size();
+        pw.print(prefix); pw.print("mSessionLogs: "); pw.println(requestLogsSizes);
+        for (int i = 0; i < requestLogsSizes; i++) {
+            final int requestId = mRequestLogs.keyAt(i);
+            final LogMaker log = mRequestLogs.valueAt(i);
+            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(": req=");
+            pw.print(requestId); pw.print(", log=" ); dumpRequestLog(pw, log); pw.println();
+        }
         pw.print(prefix); pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
@@ -2532,6 +2585,56 @@
         mRemoteFillService.dump(prefix, pw);
     }
 
+    private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
+        pw.print("CAT="); pw.print(log.getCategory());
+        pw.print(", TYPE=");
+        final int type = log.getType();
+        switch (type) {
+            case MetricsEvent.TYPE_SUCCESS: pw.print("SUCCESS"); break;
+            case MetricsEvent.TYPE_FAILURE: pw.print("FAILURE"); break;
+            case MetricsEvent.TYPE_CLOSE: pw.print("CLOSE"); break;
+            default: pw.print("UNSUPPORTED");
+        }
+        pw.print('('); pw.print(type); pw.print(')');
+        pw.print(", PKG="); pw.print(log.getPackageName());
+        pw.print(", SERVICE="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
+        pw.print(", ORDINAL="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
+        dumpNumericValue(pw, log, "FLAGS", MetricsEvent.FIELD_AUTOFILL_FLAGS);
+        dumpNumericValue(pw, log, "NUM_DATASETS", MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS);
+        dumpNumericValue(pw, log, "UI_LATENCY", MetricsEvent.FIELD_AUTOFILL_DURATION);
+        final int authStatus =
+                getNumericValue(log, MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS);
+        if (authStatus != 0) {
+            pw.print(", AUTH_STATUS=");
+            switch (authStatus) {
+                case MetricsEvent.AUTOFILL_AUTHENTICATED:
+                    pw.print("AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED:
+                    pw.print("DATASET_AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION:
+                    pw.print("INVALID_AUTHENTICATION"); break;
+                case MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION:
+                    pw.print("INVALID_DATASET_AUTHENTICATION"); break;
+                default: pw.print("UNSUPPORTED");
+            }
+            pw.print('('); pw.print(authStatus); pw.print(')');
+        }
+        dumpNumericValue(pw, log, "FC_IDS",
+                MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
+        dumpNumericValue(pw, log, "COMPAT_MODE",
+                MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
+    }
+
+    private static void dumpNumericValue(@NonNull PrintWriter pw, @NonNull LogMaker log,
+            @NonNull String field, int tag) {
+        final int value = getNumericValue(log, tag);
+        if (value != 0) {
+            pw.print(", "); pw.print(field); pw.print('='); pw.print(value);
+        }
+    }
+
     void autoFillApp(Dataset dataset) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2610,7 +2713,19 @@
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
-        writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
+
+        // Log metrics
+        final int totalRequests = mRequestLogs.size();
+        if (totalRequests > 0) {
+            if (sVerbose) Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " requests");
+            for (int i = 0; i < totalRequests; i++) {
+                final LogMaker log = mRequestLogs.valueAt(i);
+                mMetricsLogger.write(log);
+            }
+        }
+        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests));
+
         return mRemoteFillService;
     }
 
@@ -2719,14 +2834,36 @@
     }
 
     private LogMaker newLogMaker(int category, String servicePackageName) {
-        return Helper.newLogMaker(category, mComponentName.getPackageName(), servicePackageName,
-                mCompatMode);
+        return Helper.newLogMaker(category, mComponentName, servicePackageName, id, mCompatMode);
     }
 
     private void writeLog(int category) {
         mMetricsLogger.write(newLogMaker(category));
     }
 
+    private void logAuthenticationStatusLocked(int requestId, int status) {
+        addTaggedDataToRequestLogLocked(requestId,
+                MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
+    }
+
+    private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
+        final LogMaker requestLog = mRequestLogs.get(requestId);
+        if (requestLog == null) {
+            Slog.w(TAG,
+                    "addTaggedDataToRequestLogLocked(tag=" + tag + "): no log for id " + requestId);
+            return;
+        }
+        requestLog.addTaggedData(tag, value);
+    }
+
+    private static String requestLogToString(@NonNull LogMaker log) {
+        final StringWriter sw = new StringWriter();
+        final PrintWriter pw = new PrintWriter(sw);
+        dumpRequestLog(pw, log);
+        pw.flush();
+        return sw.toString();
+    }
+
     private void wtf(@Nullable Exception e, String fmt, Object...args) {
         final String message = String.format(fmt, args);
         mWtfHistory.log(message);
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index cff1a84..bb97e4a 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -19,6 +19,7 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static com.android.server.autofill.Helper.sDebug;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.service.autofill.FillResponse;
@@ -40,7 +41,7 @@
         /**
          * Called when the fill UI is ready to be shown for this view.
          */
-        void onFillReady(FillResponse fillResponse, AutofillId focusedId,
+        void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
                 @Nullable AutofillValue value);
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 811d87be..c5e838a 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
 import android.graphics.drawable.Drawable;
@@ -162,22 +163,25 @@
      * @param response the current fill response
      * @param filterText text of the view to be filled
      * @param servicePackageName package name of the autofill service filling the activity
-     * @param packageName package name of the activity that is filled
+     * @param componentName component name of the activity that is filled
      * @param serviceLabel label of autofill service
      * @param serviceIcon icon of autofill service
-     * @param callback Identifier for the caller
+     * @param callback identifier for the caller
+     * @param sessionId id of the autofill session
+     * @param compatMode whether the app is being autofilled in compatibility mode.
      */
     public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
             @Nullable String filterText, @Nullable String servicePackageName,
-            @NonNull String packageName, @NonNull CharSequence serviceLabel,
-            @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, boolean compatMode) {
+            @NonNull ComponentName componentName, @NonNull CharSequence serviceLabel,
+            @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, int sessionId,
+            boolean compatMode) {
         if (sDebug) {
             final int size = filterText == null ? 0 : filterText.length();
             Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
         }
         final LogMaker log = Helper
-                .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName,
-                        compatMode)
+                .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, componentName, servicePackageName,
+                        sessionId, compatMode)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
                         filterText == null ? 0 : filterText.length())
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
@@ -262,17 +266,19 @@
      */
     public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
             @Nullable String servicePackageName, @NonNull SaveInfo info,
-            @NonNull ValueFinder valueFinder, @NonNull String packageName,
+            @NonNull ValueFinder valueFinder, @NonNull ComponentName componentName,
             @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi,
             boolean compatMode) {
-        if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
+        if (sVerbose) {
+            Slog.v(TAG, "showSaveUi() for " + componentName.toShortString() + ": " + info);
+        }
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
         numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
 
         final LogMaker log = Helper
-                .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName,
-                        compatMode)
+                .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, componentName, servicePackageName,
+                        pendingSaveUi.sessionId, compatMode)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
 
         mHandler.post(() -> {
@@ -281,7 +287,7 @@
             }
             hideAllUiThread(callback);
             mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon,
-                    servicePackageName, packageName, info, valueFinder, mOverlayControl,
+                    servicePackageName, componentName, info, valueFinder, mOverlayControl,
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
@@ -409,7 +415,7 @@
         if (pendingSaveUi != null && notifyClient) {
             try {
                 if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
-                pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
+                pendingSaveUi.client.setSaveUiState(pendingSaveUi.sessionId, false);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client to set save UI state to hidden: " + e);
             }
diff --git a/services/autofill/java/com/android/server/autofill/ui/PendingUi.java b/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
index d1dfb5c..091208b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
@@ -35,7 +35,7 @@
 
     private final IBinder mToken;
     private int mState;
-    public final int id;
+    public final int sessionId;
     public final IAutoFillManagerClient client;
 
     /**
@@ -43,10 +43,11 @@
      *
      * @param token token used to identify this pending UI.
      */
-    public PendingUi(@NonNull IBinder token, int id, @NonNull IAutoFillManagerClient client) {
+    public PendingUi(@NonNull IBinder token, int sessionId,
+            @NonNull IAutoFillManagerClient client) {
         mToken = token;
         mState = STATE_CREATED;
-        this.id = id;
+        this.sessionId = sessionId;
         this.client = client;
     }
 
@@ -81,7 +82,7 @@
 
     @Override
     public String toString() {
-        return "PendingUi: [token=" + mToken + ", id=" + id + ", state="
+        return "PendingUi: [token=" + mToken + ", sessionId=" + sessionId + ", state="
                 + DebugUtils.flagsToString(PendingUi.class, "STATE_", mState) + "]";
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index a5311b2..dc84498 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.app.Dialog;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -133,14 +134,14 @@
     private final CharSequence mSubTitle;
     private final PendingUi mPendingUi;
     private final String mServicePackageName;
-    private final String mPackageName;
+    private final ComponentName mComponentName;
     private final boolean mCompatMode;
 
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi,
            @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
-           @Nullable String servicePackageName, @NonNull String packageName,
+           @Nullable String servicePackageName, @NonNull ComponentName componentName,
            @NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
            @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
            boolean compatMode) {
@@ -148,7 +149,7 @@
         mListener = new OneTimeListener(listener);
         mOverlayControl = overlayControl;
         mServicePackageName = servicePackageName;
-        mPackageName = packageName;
+        mComponentName = componentName;
         mCompatMode = compatMode;
 
         context = new ContextThemeWrapper(context, THEME_ID);
@@ -412,12 +413,12 @@
     }
 
     private LogMaker newLogMaker(int category, int saveType) {
-        return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
+        return newLogMaker(category).addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
     }
 
     private LogMaker newLogMaker(int category) {
-        return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode);
+        return Helper.newLogMaker(category, mComponentName, mServicePackageName,
+                mPendingUi.sessionId, mCompatMode);
     }
 
     private void writeLog(int category, int saveType) {
@@ -505,7 +506,7 @@
         pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
         pw.print(prefix); pw.print("pendingUi: "); pw.println(mPendingUi);
         pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName);
-        pw.print(prefix); pw.print("app: "); pw.println(mPackageName);
+        pw.print(prefix); pw.print("app: "); pw.println(mComponentName.toShortString());
         pw.print(prefix); pw.print("compat mode: "); pw.println(mCompatMode);
 
         final View view = mDialog.getWindow().getDecorView();
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0775abf..f79a51b 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1776,7 +1776,7 @@
             } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
                     || UserHandle.isSameApp(callingUid, mSystemUiUid)
                     || ((mAppStateTracker != null)
-                        && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) {
+                        && mAppStateTracker.isUidPowerSaveUserWhitelisted(callingUid)))) {
                 flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                 flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 9b001ce..3a7b5d6 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -117,6 +117,12 @@
     @GuardedBy("mLock")
     private int[] mPowerWhitelistedAllAppIds = new int[0];
 
+    /**
+     * User whitelisted apps in the device idle controller.
+     */
+    @GuardedBy("mLock")
+    private int[] mPowerWhitelistedUserAppIds = new int[0];
+
     @GuardedBy("mLock")
     private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
 
@@ -983,13 +989,16 @@
      * Called by device idle controller to update the power save whitelists.
      */
     public void setPowerSaveWhitelistAppIds(
-            int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
+            int[] powerSaveWhitelistExceptIdleAppIdArray,
+            int[] powerSaveWhitelistUserAppIdArray,
+            int[] tempWhitelistAppIdArray) {
         synchronized (mLock) {
             final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
             final int[] previousTempWhitelist = mTempWhitelistedAppIds;
 
-            mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
+            mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
             mTempWhitelistedAppIds = tempWhitelistAppIdArray;
+            mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
 
             if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
                 mHandler.notifyAllUnwhitelisted();
@@ -1194,6 +1203,16 @@
     }
 
     /**
+     * @param uid the uid to check for
+     * @return whether a UID is in the user defined power-save whitelist or not.
+     */
+    public boolean isUidPowerSaveUserWhitelisted(int uid) {
+        synchronized (mLock) {
+            return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
+        }
+    }
+
+    /**
      * @return whether a UID is in the temp power-save whitelist or not.
      *
      * Note clients normally shouldn't need to access it. It's only for dumpsys.
@@ -1231,9 +1250,12 @@
             pw.print("Foreground uids: ");
             dumpUids(pw, mForegroundUids);
 
-            pw.print("Whitelist appids: ");
+            pw.print("Except-idle + user whitelist appids: ");
             pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
 
+            pw.print("User whitelist appids: ");
+            pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
+
             pw.print("Temp whitelist appids: ");
             pw.println(Arrays.toString(mTempWhitelistedAppIds));
 
@@ -1311,6 +1333,10 @@
                 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
+            for (int appId : mPowerWhitelistedUserAppIds) {
+                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+            }
+
             for (int appId : mTempWhitelistedAppIds) {
                 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 74b4543..0f4702c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1540,7 +1540,7 @@
 
                 mLocalActivityManager.registerScreenObserver(mScreenObserver);
 
-                passWhiteListToForceAppStandbyTrackerLocked();
+                passWhiteListsToForceAppStandbyTrackerLocked();
                 updateInteractivityLocked();
             }
             updateConnectivityState(null);
@@ -1631,7 +1631,7 @@
                             mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
                             mPowerSaveWhitelistExceptIdleAppIds);
 
-                    passWhiteListToForceAppStandbyTrackerLocked();
+                    passWhiteListsToForceAppStandbyTrackerLocked();
                 }
                 return true;
             } catch (PackageManager.NameNotFoundException e) {
@@ -1650,7 +1650,7 @@
                         mPowerSaveWhitelistExceptIdleAppIds);
                 mPowerSaveWhitelistUserAppsExceptIdle.clear();
 
-                passWhiteListToForceAppStandbyTrackerLocked();
+                passWhiteListsToForceAppStandbyTrackerLocked();
             }
         }
     }
@@ -2589,7 +2589,7 @@
             }
             mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
         }
-        passWhiteListToForceAppStandbyTrackerLocked();
+        passWhiteListsToForceAppStandbyTrackerLocked();
     }
 
     private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
@@ -2615,7 +2615,7 @@
             }
             mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
         }
-        passWhiteListToForceAppStandbyTrackerLocked();
+        passWhiteListsToForceAppStandbyTrackerLocked();
     }
 
     private void reportPowerSaveWhitelistChangedLocked() {
@@ -2630,9 +2630,10 @@
         getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
     }
 
-    private void passWhiteListToForceAppStandbyTrackerLocked() {
+    private void passWhiteListsToForceAppStandbyTrackerLocked() {
         mAppStateTracker.setPowerSaveWhitelistAppIds(
                 mPowerSaveWhitelistExceptIdleAppIdArray,
+                mPowerSaveWhitelistUserAppIdArray,
                 mTempWhitelistAppIdArray);
     }
 
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d7057f4..2c9a494 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1310,10 +1310,10 @@
                 : ActivityManager.PROCESS_STATE_NONEXISTENT;
 
         if (procState <= ActivityManager.PROCESS_STATE_TOP) {
-            return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
+            return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
         }
         if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-            return ContentResolver.SYNC_EXEMPTION_ACTIVE;
+            return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
         }
         return ContentResolver.SYNC_EXEMPTION_NONE;
     }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 33cf11b..0a640b8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1656,7 +1656,7 @@
         }
 
         if (syncOperation.syncExemptionFlag
-                == ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP) {
+                == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
             DeviceIdleController.LocalService dic =
                     LocalServices.getService(DeviceIdleController.LocalService.class);
             if (dic != null) {
@@ -1668,6 +1668,15 @@
             }
         }
 
+        if (syncOperation.isAppStandbyExempted()) {
+            final UsageStatsManagerInternal usmi = LocalServices.getService(
+                    UsageStatsManagerInternal.class);
+            if (usmi != null) {
+                usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
+                        UserHandle.getUserId(syncOperation.owningUid));
+            }
+        }
+
         getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
                 syncOperation.target.userId, syncOperation.wakeLockName());
     }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index d097563..25edf40 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -390,10 +390,10 @@
         switch (syncExemptionFlag) {
             case ContentResolver.SYNC_EXEMPTION_NONE:
                 break;
-            case ContentResolver.SYNC_EXEMPTION_ACTIVE:
+            case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
                 sb.append(" STANDBY-EXEMPTED");
                 break;
-            case ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP:
+            case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
                 sb.append(" STANDBY-EXEMPTED(TOP)");
                 break;
             default:
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 6a343f8..11f0701 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -341,6 +341,7 @@
         boolean initialization;
         Bundle extras;
         int reason;
+        int syncExemptionFlag;
     }
 
     public static class DayStats {
@@ -1142,6 +1143,7 @@
             item.reason = op.reason;
             item.extras = op.extras;
             item.event = EVENT_START;
+            item.syncExemptionFlag = op.syncExemptionFlag;
             mSyncHistory.add(0, item);
             while (mSyncHistory.size() > MAX_HISTORY) {
                 mSyncHistory.remove(mSyncHistory.size()-1);
@@ -1262,6 +1264,20 @@
             SyncManager.formatDurationHMS(event, elapsedTime);
             event.append(" Reason=");
             event.append(SyncOperation.reasonToString(null, item.reason));
+            if (item.syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE) {
+                event.append(" Exemption=");
+                switch (item.syncExemptionFlag) {
+                    case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
+                        event.append("fg");
+                        break;
+                    case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
+                        event.append("top");
+                        break;
+                    default:
+                        event.append(item.syncExemptionFlag);
+                        break;
+                }
+            }
             event.append(" Extras=");
             SyncOperation.extrasToStringBuilder(item.extras, event);
 
diff --git a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index 5daacd7..933b3d6 100644
--- a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -445,7 +445,7 @@
         areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {UID_2});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2});
 
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
@@ -482,6 +482,15 @@
     }
 
     @Test
+    public void testPowerSaveUserWhitelist() throws Exception {
+        final AppStateTrackerTestable instance = newInstance();
+        instance.setPowerSaveWhitelistAppIds(new int[] {}, new int[] {UID_1, UID_2}, new int[] {});
+        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_1));
+        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_2));
+        assertFalse(instance.isUidPowerSaveUserWhitelisted(UID_3));
+    }
+
+    @Test
     public void testUidStateForeground() throws Exception {
         final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
@@ -861,7 +870,7 @@
         // -------------------------------------------------------------------------
         // Tests with system/user/temp whitelist.
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -873,7 +882,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -886,7 +895,8 @@
         reset(l);
 
         // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -898,7 +908,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -924,7 +934,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         // Called once for updating all whitelist and once for updating temp whitelist
@@ -937,7 +947,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -950,7 +960,8 @@
         reset(l);
 
         // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -962,7 +973,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
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 dee2556..8461166 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -218,6 +218,11 @@
                     + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
         }
 
+        @Override
+        public boolean isDeviceIdleMode() {
+            return false;
+        }
+
         // Internal methods
 
         void setDisplayOn(boolean on) {
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3378897..9c62700 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -24,6 +24,8 @@
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -194,8 +196,9 @@
     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
-    static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
-    static final int MSG_UPDATE_STABLE_CHARGING= 13;
+    static final int MSG_REPORT_EXEMPTED_SYNC_SCHEDULED = 12;
+    static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
+    static final int MSG_UPDATE_STABLE_CHARGING= 14;
 
     long mCheckIdleIntervalMillis;
     long mAppIdleParoleIntervalMillis;
@@ -213,8 +216,20 @@
     long mPredictionTimeoutMillis;
     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
     long mSyncAdapterTimeoutMillis;
-    /** Maximum time an exempted sync should keep the buckets elevated. */
-    long mExemptedSyncAdapterTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+     * non-doze
+     */
+    long mExemptedSyncScheduledNonDozeTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+     * doze
+     */
+    long mExemptedSyncScheduledDozeTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
+     */
+    long mExemptedSyncStartTimeoutMillis;
     /** Maximum time a system interaction should keep the buckets elevated. */
     long mSystemInteractionTimeoutMillis;
     /** The length of time phone must be charging before considered stable enough to run jobs  */
@@ -393,6 +408,37 @@
         }
     }
 
+    void reportExemptedSyncScheduled(String packageName, int userId) {
+        if (!mAppIdleEnabled) return;
+
+        final int bucketToPromote;
+        final int usageReason;
+        final long durationMillis;
+
+        if (!mInjector.isDeviceIdleMode()) {
+            // Not dozing.
+            bucketToPromote = STANDBY_BUCKET_ACTIVE;
+            usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
+            durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
+        } else {
+            // Dozing.
+            bucketToPromote = STANDBY_BUCKET_WORKING_SET;
+            usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+            durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
+        }
+
+        final long elapsedRealtime = mInjector.elapsedRealtime();
+
+        synchronized (mAppIdleLock) {
+            AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
+                    bucketToPromote, usageReason,
+                    0,
+                    elapsedRealtime + durationMillis);
+            maybeInformListeners(packageName, userId, elapsedRealtime,
+                    appUsage.currentBucket, appUsage.bucketingReason, false);
+        }
+    }
+
     void reportExemptedSyncStart(String packageName, int userId) {
         if (!mAppIdleEnabled) return;
 
@@ -402,7 +448,7 @@
             AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                     STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START,
                     0,
-                    elapsedRealtime + mExemptedSyncAdapterTimeoutMillis);
+                    elapsedRealtime + mExemptedSyncStartTimeoutMillis);
             maybeInformListeners(packageName, userId, elapsedRealtime,
                     appUsage.currentBucket, appUsage.bucketingReason, false);
         }
@@ -1365,6 +1411,11 @@
                 .sendToTarget();
     }
 
+    void postReportExemptedSyncScheduled(String packageName, int userId) {
+        mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_SCHEDULED, userId, 0, packageName)
+                .sendToTarget();
+    }
+
     void postReportExemptedSyncStart(String packageName, int userId) {
         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
                 .sendToTarget();
@@ -1401,6 +1452,16 @@
         TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
         pw.println();
 
+        pw.print("  mExemptedSyncScheduledNonDozeTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
+        pw.println();
+        pw.print("  mExemptedSyncScheduledDozeTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
+        pw.println();
+        pw.print("  mExemptedSyncStartTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
+        pw.println();
+
         pw.println();
         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
         pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
@@ -1429,6 +1490,7 @@
         private IBatteryStats mBatteryStats;
         private PackageManagerInternal mPackageManagerInternal;
         private DisplayManager mDisplayManager;
+        private PowerManager mPowerManager;
         int mBootPhase;
 
         Injector(Context context, Looper looper) {
@@ -1453,6 +1515,7 @@
                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
                 mDisplayManager = (DisplayManager) mContext.getSystemService(
                         Context.DISPLAY_SERVICE);
+                mPowerManager = mContext.getSystemService(PowerManager.class);
             }
             mBootPhase = phase;
         }
@@ -1532,6 +1595,11 @@
             return Global.getString(mContext.getContentResolver(),
                     Global.APP_IDLE_CONSTANTS);
         }
+
+        /** Whether the device is in doze or not. */
+        public boolean isDeviceIdleMode() {
+            return mPowerManager.isDeviceIdleMode();
+        }
     }
 
     class AppStandbyHandler extends Handler {
@@ -1595,6 +1663,10 @@
                             mInjector.elapsedRealtime());
                     break;
 
+                case MSG_REPORT_EXEMPTED_SYNC_SCHEDULED:
+                    reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
+                    break;
+
                 case MSG_REPORT_EXEMPTED_SYNC_START:
                     reportExemptedSyncStart((String) msg.obj, msg.arg1);
                     break;
@@ -1684,7 +1756,12 @@
                 "system_update_usage_duration";
         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
         private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
-        private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
+        private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION
+                = "exempted_sync_scheduled_nd_duration";
+        private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION
+                = "exempted_sync_scheduled_d_duration";
+        private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION
+                = "exempted_sync_start_duration";
         private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
                 "system_interaction_duration";
         private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
@@ -1693,7 +1770,9 @@
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
-        public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
+        public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1778,9 +1857,22 @@
                 mSyncAdapterTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYNC_ADAPTER_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
-                mExemptedSyncAdapterTimeoutMillis = mParser.getDurationMillis
-                        (KEY_EXEMPTED_SYNC_HOLD_DURATION,
-                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_EXEMPTED_SYNC_TIMEOUT);
+
+                mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
+                                COMPRESS_TIME ? (ONE_MINUTE / 2)
+                                        : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
+
+                mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE
+                                        : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
+
+                mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE
+                                        : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
+
                 mSystemInteractionTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYSTEM_INTERACTION_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 6311127a..a7d3f78 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1371,6 +1371,11 @@
         }
 
         @Override
+        public void reportExemptedSyncScheduled(String packageName, int userId) {
+            mAppStandby.postReportExemptedSyncScheduled(packageName, userId);
+        }
+
+        @Override
         public void reportExemptedSyncStart(String packageName, int userId) {
             mAppStandby.postReportExemptedSyncStart(packageName, userId);
         }