Merge changes I61178def,I536e8934

* changes:
  Flip feature flag to enable StrictMode defaults.
  Narrower StrictMode defaults.
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index f6b6b86..1ce89d2 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -21,6 +21,7 @@
 import android.annotation.StringDef;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
+import android.app.slice.widget.SliceView;
 import android.content.ContentResolver;
 import android.content.IContentProvider;
 import android.graphics.drawable.Icon;
@@ -54,7 +55,12 @@
     public @interface SliceHint{ }
 
     /**
-     * Hint that this content is a title of other content in the slice.
+     * Hint that this content is a title of other content in the slice. This can also indicate that
+     * the content should be used in the shortcut representation of the slice (icon, label, action),
+     * normally this should be indicated by adding the hint on the action containing that content.
+     *
+     * @see SliceView#MODE_SHORTCUT
+     * @see SliceItem#TYPE_ACTION
      */
     public static final String HINT_TITLE       = "title";
     /**
@@ -100,6 +106,13 @@
      */
     public static final String HINT_NO_TINT     = "no_tint";
     /**
+     * Hint to indicate that this content should not be shown in the {@link SliceView#MODE_SMALL}
+     * and {@link SliceView#MODE_LARGE} modes of SliceView. This content may be used to populate
+     * the {@link SliceView#MODE_SHORTCUT} format of the slice.
+     * @hide
+     */
+    public static final String HINT_HIDDEN = "hidden";
+    /**
      * Hint to indicate that this slice is incomplete and an update will be sent once
      * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the
      * OS and should not be cached by apps.
diff --git a/core/java/android/app/slice/widget/GridView.java b/core/java/android/app/slice/widget/GridView.java
index 67a3c67..793abc0 100644
--- a/core/java/android/app/slice/widget/GridView.java
+++ b/core/java/android/app/slice/widget/GridView.java
@@ -126,6 +126,9 @@
      * Returns true if this item is just an image.
      */
     private boolean addItem(SliceItem item) {
+        if (item.hasHint(Slice.HINT_HIDDEN)) {
+            return false;
+        }
         if (item.getType() == SliceItem.TYPE_IMAGE) {
             ImageView v = new ImageView(getContext());
             v.setImageIcon(item.getIcon());
@@ -145,6 +148,9 @@
                 items.addAll(item.getSlice().getItems());
             }
             items.forEach(i -> {
+                if (i.hasHint(Slice.HINT_HIDDEN)) {
+                    return;
+                }
                 Context context = getContext();
                 switch (i.getType()) {
                     case SliceItem.TYPE_TEXT:
diff --git a/core/java/android/app/slice/widget/LargeTemplateView.java b/core/java/android/app/slice/widget/LargeTemplateView.java
index f45b2a8..788f6fb 100644
--- a/core/java/android/app/slice/widget/LargeTemplateView.java
+++ b/core/java/android/app/slice/widget/LargeTemplateView.java
@@ -85,9 +85,14 @@
             addList(slice, items);
         } else {
             slice.getItems().forEach(item -> {
-                if (item.hasHint(Slice.HINT_ACTIONS)) {
+                if (item.hasHint(Slice.HINT_HIDDEN)) {
+                    // If it's hidden we don't show it
+                    return;
+                } else if (item.hasHint(Slice.HINT_ACTIONS)) {
+                    // Action groups don't show in lists
                     return;
                 } else if (item.getType() == SliceItem.TYPE_COLOR) {
+                    // A color is not a list item
                     return;
                 } else if (item.getType() == SliceItem.TYPE_SLICE
                         && item.hasHint(Slice.HINT_LIST)) {
@@ -108,8 +113,12 @@
 
     private void addList(Slice slice, List<SliceItem> items) {
         List<SliceItem> sliceItems = slice.getItems();
-        sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
-        items.addAll(sliceItems);
+        sliceItems.forEach(i -> {
+            if (!i.hasHint(Slice.HINT_HIDDEN) && i.getType() != SliceItem.TYPE_COLOR) {
+                i.addHint(Slice.HINT_LIST_ITEM);
+                items.add(i);
+            }
+        });
     }
 
     /**
diff --git a/core/java/android/app/slice/widget/ShortcutView.java b/core/java/android/app/slice/widget/ShortcutView.java
index 0bca8ce..0b7ad0d 100644
--- a/core/java/android/app/slice/widget/ShortcutView.java
+++ b/core/java/android/app/slice/widget/ShortcutView.java
@@ -24,13 +24,20 @@
 import android.app.slice.widget.SliceView.SliceModeView;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.OvalShape;
 import android.net.Uri;
 
 import com.android.internal.R;
 
+import java.util.List;
+
 /**
  * @hide
  */
@@ -38,27 +45,26 @@
 
     private static final String TAG = "ShortcutView";
 
-    private PendingIntent mAction;
     private Uri mUri;
+    private PendingIntent mAction;
+    private SliceItem mLabel;
+    private SliceItem mIcon;
+
     private int mLargeIconSize;
     private int mSmallIconSize;
 
     public ShortcutView(Context context) {
         super(context);
-        mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
+        final Resources res = getResources();
+        mSmallIconSize = res.getDimensionPixelSize(R.dimen.slice_icon_size);
+        mLargeIconSize = res.getDimensionPixelSize(R.dimen.slice_shortcut_size);
     }
 
     @Override
     public void setSlice(Slice slice) {
         removeAllViews();
-        SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
-        SliceItem iconItem = SliceQuery.getPrimaryIcon(slice);
-        SliceItem textItem = sliceItem != null
-                ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT)
-                : SliceQuery.find(slice, SliceItem.TYPE_TEXT);
-        SliceItem colorItem = sliceItem != null
-                ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR)
-                : SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+        determineShortcutItems(getContext(), slice);
+        SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
         if (colorItem == null) {
             colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
         }
@@ -67,13 +73,11 @@
         ShapeDrawable circle = new ShapeDrawable(new OvalShape());
         circle.setTint(color);
         setBackground(circle);
-        if (iconItem != null) {
-            final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE);
+        if (mIcon != null) {
+            final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE);
             final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
-            SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(),
+            SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(),
                     isLarge, this /* parent */);
-            mAction = sliceItem != null ? sliceItem.getAction()
-                    : null;
             mUri = slice.getUri();
             setClickable(true);
         } else {
@@ -103,4 +107,69 @@
         }
         return true;
     }
+
+    /**
+     * Looks at the slice and determines which items are best to use to compose the shortcut.
+     */
+    private void determineShortcutItems(Context context, Slice slice) {
+        List<String> h = slice.getHints();
+        SliceItem sliceItem = new SliceItem(slice, SliceItem.TYPE_SLICE,
+                h.toArray(new String[h.size()]));
+        SliceItem titleItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION,
+                Slice.HINT_TITLE, null);
+
+        if (titleItem != null) {
+            // Preferred case: hinted action containing hinted image and text
+            mAction = titleItem.getAction();
+            mIcon = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+                    null);
+            mLabel = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+                    null);
+        } else {
+            // No hinted action; just use the first one
+            SliceItem actionItem = SliceQuery.find(sliceItem, SliceItem.TYPE_ACTION, (String) null,
+                    null);
+            mAction = (actionItem != null) ? actionItem.getAction() : null;
+        }
+        // First fallback: any hinted image and text
+        if (mIcon == null) {
+            mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+                    null);
+        }
+        if (mLabel == null) {
+            mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+                    null);
+        }
+        // Second fallback: first image and text
+        if (mIcon == null) {
+            mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, (String) null,
+                    null);
+        }
+        if (mLabel == null) {
+            mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, (String) null,
+                    null);
+        }
+        // Final fallback: use app info
+        if (mIcon == null || mLabel == null || mAction == null) {
+            PackageManager pm = context.getPackageManager();
+            ProviderInfo providerInfo = pm.resolveContentProvider(
+                    slice.getUri().getAuthority(), 0);
+            ApplicationInfo appInfo = providerInfo.applicationInfo;
+            if (appInfo != null) {
+                if (mIcon == null) {
+                    Drawable icon = appInfo.loadDefaultIcon(pm);
+                    mIcon = new SliceItem(SliceViewUtil.createIconFromDrawable(icon),
+                            SliceItem.TYPE_IMAGE, new String[] {Slice.HINT_LARGE});
+                }
+                if (mLabel == null) {
+                    mLabel = new SliceItem(pm.getApplicationLabel(appInfo),
+                            SliceItem.TYPE_TEXT, null);
+                }
+                if (mAction == null) {
+                    mAction = PendingIntent.getActivity(context, 0,
+                            pm.getLaunchIntentForPackage(appInfo.packageName), 0);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/slice/widget/SliceView.java b/core/java/android/app/slice/widget/SliceView.java
index 5bafbc0..c583562 100644
--- a/core/java/android/app/slice/widget/SliceView.java
+++ b/core/java/android/app/slice/widget/SliceView.java
@@ -115,7 +115,9 @@
      */
     public static final String MODE_LARGE       = "SLICE_LARGE";
     /**
-     * Mode indicating this slice should be presented as an icon.
+     * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
+     * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a
+     * slice.
      */
     public static final String MODE_SHORTCUT    = "SLICE_ICON";
 
diff --git a/core/java/android/app/slice/widget/SliceViewUtil.java b/core/java/android/app/slice/widget/SliceViewUtil.java
index 0366998..1cf0055 100644
--- a/core/java/android/app/slice/widget/SliceViewUtil.java
+++ b/core/java/android/app/slice/widget/SliceViewUtil.java
@@ -28,6 +28,7 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.view.Gravity;
@@ -141,6 +142,21 @@
     /**
      * @hide
      */
+    public static Icon createIconFromDrawable(Drawable d) {
+        if (d instanceof BitmapDrawable) {
+            return Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
+        }
+        Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(b);
+        d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        d.draw(canvas);
+        return Icon.createWithBitmap(b);
+    }
+
+    /**
+     * @hide
+     */
     public static void createCircledIcon(Context context, int color, int iconSize, Icon icon,
             boolean isLarge, ViewGroup parent) {
         ImageView v = new ImageView(context);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d138184..a3c927a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4671,6 +4671,11 @@
     // OS: P
     DIALOG_SIM_STATUS = 1246;
 
+    // OPEN: Settings > System > About Phone > Android Version
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_FIRMWARE_VERSION = 1247;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index ad30897..1b61866 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -56,6 +56,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UEventObserver;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -246,6 +247,7 @@
     }
 
     private void registerHealthCallback() {
+        traceBegin("HealthInitWrapper");
         mHealthServiceWrapper = new HealthServiceWrapper();
         mHealthHalCallback = new HealthHalCallback();
         // IHealth is lazily retrieved.
@@ -259,8 +261,11 @@
         } catch (NoSuchElementException ex) {
             Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
             throw ex;
+        } finally {
+            traceEnd();
         }
 
+        traceBegin("HealthInitWaitUpdate");
         // init register for new service notifications, and IServiceManager should return the
         // existing service in a near future. Wait for this.update() to instantiate
         // the initial mHealthInfo.
@@ -280,6 +285,7 @@
 
         Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
                 + "ms and received the update.");
+        traceEnd();
     }
 
     private void updateBatteryWarningLevelLocked() {
@@ -375,6 +381,7 @@
     }
 
     private void update(HealthInfo info) {
+        traceBegin("HealthInfoUpdate");
         synchronized (mLock) {
             if (!mUpdatesStopped) {
                 mHealthInfo = info;
@@ -385,6 +392,7 @@
                 copy(mLastHealthInfo, info);
             }
         }
+        traceEnd();
     }
 
     private static void copy(HealthInfo dst, HealthInfo src) {
@@ -932,6 +940,14 @@
         proto.flush();
     }
 
+    private static void traceBegin(String name) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+    }
+
+    private static void traceEnd() {
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+    }
+
     private final class Led {
         private final Light mBatteryLight;
 
@@ -997,6 +1013,7 @@
                 String instance) {
             if (newService == null) return;
 
+            traceBegin("HealthUnregisterCallback");
             try {
                 if (oldService != null) {
                     int r = oldService.unregisterCallback(this);
@@ -1008,8 +1025,11 @@
             } catch (RemoteException ex) {
                 Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
                             + ex.getMessage());
+            } finally {
+                traceEnd();
             }
 
+            traceBegin("HealthRegisterCallback");
             try {
                 int r = newService.registerCallback(this);
                 if (r != Result.SUCCESS) {
@@ -1022,6 +1042,8 @@
             } catch (RemoteException ex) {
                 Slog.e(TAG, "health: cannot register callback (transaction error): "
                         + ex.getMessage());
+            } finally {
+                traceEnd();
             }
         }
     }
@@ -1054,53 +1076,63 @@
             Slog.e(TAG, "health: must not call unregisterListener on battery properties");
         }
         public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
-            IHealth service = mHealthServiceWrapper.getLastService();
-            if (service == null) throw new RemoteException("no health service");
-            final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
-            switch(id) {
-                case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
-                    service.getChargeCounter((int result, int value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
-                case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
-                    service.getCurrentNow((int result, int value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
-                case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
-                    service.getCurrentAverage((int result, int value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
-                case BatteryManager.BATTERY_PROPERTY_CAPACITY:
-                    service.getCapacity((int result, int value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
-                case BatteryManager.BATTERY_PROPERTY_STATUS:
-                    service.getChargeStatus((int result, int value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
-                case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
-                    service.getEnergyCounter((int result, long value) -> {
-                        outResult.value = result;
-                        if (result == Result.SUCCESS) prop.setLong(value);
-                    });
-                    break;
+            traceBegin("HealthGetProperty");
+            try {
+                IHealth service = mHealthServiceWrapper.getLastService();
+                if (service == null) throw new RemoteException("no health service");
+                final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+                switch(id) {
+                    case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+                        service.getChargeCounter((int result, int value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                    case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+                        service.getCurrentNow((int result, int value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                    case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+                        service.getCurrentAverage((int result, int value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                    case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+                        service.getCapacity((int result, int value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                    case BatteryManager.BATTERY_PROPERTY_STATUS:
+                        service.getChargeStatus((int result, int value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                    case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+                        service.getEnergyCounter((int result, long value) -> {
+                            outResult.value = result;
+                            if (result == Result.SUCCESS) prop.setLong(value);
+                        });
+                        break;
+                }
+                return outResult.value;
+            } finally {
+                traceEnd();
             }
-            return outResult.value;
         }
         public void scheduleUpdate() throws RemoteException {
-            IHealth service = mHealthServiceWrapper.getLastService();
-            if (service == null) throw new RemoteException("no health service");
-            service.update();
+            traceBegin("HealthScheduleUpdate");
+            try {
+                IHealth service = mHealthServiceWrapper.getLastService();
+                if (service == null) throw new RemoteException("no health service");
+                service.update();
+            } finally {
+                traceEnd();
+            }
         }
     }
 
@@ -1203,15 +1235,27 @@
             if (callback == null || managerSupplier == null || healthSupplier == null)
                 throw new NullPointerException();
 
+            IServiceManager manager;
+
             mCallback = callback;
             mHealthSupplier = healthSupplier;
 
-            IServiceManager manager = managerSupplier.get();
+            traceBegin("HealthInitGetManager");
+            try {
+                manager = managerSupplier.get();
+            } finally {
+                traceEnd();
+            }
             for (String name : sAllInstances) {
-                if (manager.getTransport(IHealth.kInterfaceName, name) !=
-                        IServiceManager.Transport.EMPTY) {
-                    mInstanceName = name;
-                    break;
+                traceBegin("HealthInitGetTransport_" + name);
+                try {
+                    if (manager.getTransport(IHealth.kInterfaceName, name) !=
+                            IServiceManager.Transport.EMPTY) {
+                        mInstanceName = name;
+                        break;
+                    }
+                } finally {
+                    traceEnd();
                 }
             }
 
@@ -1221,7 +1265,12 @@
                         sAllInstances.toString()));
             }
 
-            manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+            traceBegin("HealthInitRegisterNotification");
+            try {
+                manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+            } finally {
+                traceEnd();
+            }
             Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fc4cb1a..1ee92b7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4741,7 +4741,9 @@
                             mWindowManager, appOpsManager, proxy, this,
                             OP_ASSIST_STRUCTURE, OP_NONE);
                     requester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
-                            true, false /* fetchScreenshots */, recentsUid, recentsPackage);
+                            true /* fetchData */, false /* fetchScreenshots */,
+                            true /* allowFetchData */, false /* alloweFetchScreenshots */,
+                            recentsUid, recentsPackage);
                 }
 
                 final Intent intent = new Intent();
diff --git a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
index 8306731..f22fe37 100644
--- a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
+++ b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
@@ -37,17 +37,12 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "AssistDataReceiverProxy" : TAG_AM;
 
     private String mCallerPackage;
-    private boolean mBinderDied;
     private IAssistDataReceiver mReceiver;
 
     public AssistDataReceiverProxy(IAssistDataReceiver receiver, String callerPackage) {
-        try {
-            receiver.asBinder().linkToDeath(this, 0);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Could not link to client death", e);
-        }
         mReceiver = receiver;
         mCallerPackage = callerPackage;
+        linkToDeath();
     }
 
     @Override
@@ -58,7 +53,7 @@
 
     @Override
     public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
-        if (!mBinderDied) {
+        if (mReceiver != null) {
             try {
                 mReceiver.onHandleAssistData(data);
             } catch (RemoteException e) {
@@ -70,7 +65,7 @@
 
     @Override
     public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
-        if (!mBinderDied) {
+        if (mReceiver != null) {
             try {
                 mReceiver.onHandleAssistScreenshot(screenshot);
             } catch (RemoteException e) {
@@ -81,7 +76,27 @@
     }
 
     @Override
+    public void onAssistRequestCompleted() {
+        unlinkToDeath();
+    }
+
+    @Override
     public void binderDied() {
-        mBinderDied = true;
+        unlinkToDeath();
+    }
+
+    private void linkToDeath() {
+        try {
+            mReceiver.asBinder().linkToDeath(this, 0);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not link to client death", e);
+        }
+    }
+
+    private void unlinkToDeath() {
+        if (mReceiver != null) {
+            mReceiver.asBinder().unlinkToDeath(this, 0);
+        }
+        mReceiver = null;
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index e32ff6e..a8f829f 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -94,6 +94,17 @@
          */
         @GuardedBy("mCallbacksLock")
         void onAssistScreenshotReceivedLocked(Bitmap screenshot);
+
+        /**
+         * Called when there is no more pending assist data or screenshots for the last request.
+         * If the request was canceled, then this callback will not be made. In addition, the
+         * callback will be made with the {@param mCallbacksLock} held, and only if
+         * {@link #canHandleReceivedAssistDataLocked()} is true.
+         */
+        @GuardedBy("mCallbacksLock")
+        default void onAssistRequestCompleted() {
+            // Do nothing
+        }
     }
 
     /**
@@ -131,15 +142,21 @@
      * @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is
      *     true, the caller is allowed to fetch the assist data, and the current activity allows
      *     assist data to be fetched from it
+     * @param allowFetchData to be joined with other checks, determines whether or not the requester
+     *     is allowed to fetch the assist data
+     * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
+     *     requester is allowed to fetch the assist screenshot
      */
-    public void requestAssistData(List<IBinder> activityTokens, boolean fetchData,
-            boolean fetchScreenshot, int callingUid, String callingPackage) {
-        // TODO: Better handle the cancel case if a request can be reused
-        // TODO: Known issue, if the assist data is not allowed on the current activity, then no
-        //       assist data is requested for any of the other activities
+    public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
+            final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
+            int callingUid, String callingPackage) {
+        // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity,
+        //                   then no assist data is requested for any of the other activities
 
         // Early exit if there are no activity to fetch for
         if (activityTokens.isEmpty()) {
+            // No activities, just dispatch request-complete
+            tryDispatchRequestComplete();
             return;
         }
 
@@ -150,8 +167,8 @@
         } catch (RemoteException e) {
             // Should never happen
         }
-        fetchData &= isAssistDataAllowed;
-        fetchScreenshot &= fetchData && isAssistDataAllowed
+        allowFetchData &= isAssistDataAllowed;
+        allowFetchScreenshot &= fetchData && isAssistDataAllowed
                 && (mRequestScreenshotAppOps != OP_NONE);
 
         mCanceled = false;
@@ -162,7 +179,7 @@
 
         if (fetchData) {
             if (mAppOpsManager.checkOpNoThrow(mRequestStructureAppOps, callingUid, callingPackage)
-                    == MODE_ALLOWED) {
+                    == MODE_ALLOWED && allowFetchData) {
                 final int numActivities = activityTokens.size();
                 for (int i = 0; i < numActivities; i++) {
                     IBinder topActivity = activityTokens.get(i);
@@ -177,8 +194,12 @@
                             mPendingDataCount++;
                         } else if (i == 0) {
                             // Wasn't allowed... given that, let's not do the screenshot either.
-                            dispatchAssistDataReceived(null);
-                            fetchScreenshot = false;
+                            if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+                                dispatchAssistDataReceived(null);
+                            } else {
+                                mAssistData.add(null);
+                            }
+                            allowFetchScreenshot = false;
                             break;
                         }
                     } catch (RemoteException e) {
@@ -187,14 +208,18 @@
                 }
             } else {
                 // Wasn't allowed... given that, let's not do the screenshot either.
-                dispatchAssistDataReceived(null);
-                fetchScreenshot = false;
+                if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+                    dispatchAssistDataReceived(null);
+                } else {
+                    mAssistData.add(null);
+                }
+                allowFetchScreenshot = false;
             }
         }
 
         if (fetchScreenshot) {
             if (mAppOpsManager.checkOpNoThrow(mRequestScreenshotAppOps, callingUid, callingPackage)
-                    == MODE_ALLOWED) {
+                    == MODE_ALLOWED && allowFetchScreenshot) {
                 try {
                     MetricsLogger.count(mContext, "assist_with_screen", 1);
                     mPendingScreenshotCount++;
@@ -203,24 +228,38 @@
                     // Can't happen
                 }
             } else {
-                dispatchAssistScreenshotReceived(null);
+                if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+                    dispatchAssistScreenshotReceived(null);
+                } else {
+                    mAssistScreenshot.add(null);
+                }
             }
         }
+        // For the cases where we dispatch null data/screenshot due to permissions, just dispatch
+        // request-complete after those are made
+        tryDispatchRequestComplete();
     }
 
     /**
      * This call should only be made when the callbacks are capable of handling the received assist
-     * data.
+     * data. The owner is also responsible for locking before calling this method.
      */
     public void processPendingAssistData() {
+        flushPendingAssistData();
+        tryDispatchRequestComplete();
+    }
+
+    private void flushPendingAssistData() {
         final int dataCount = mAssistData.size();
         for (int i = 0; i < dataCount; i++) {
             dispatchAssistDataReceived(mAssistData.get(i));
         }
+        mAssistData.clear();
         final int screenshotsCount = mAssistScreenshot.size();
         for (int i = 0; i < screenshotsCount; i++) {
             dispatchAssistScreenshotReceived(mAssistScreenshot.get(i));
         }
+        mAssistScreenshot.clear();
     }
 
     public int getPendingDataCount() {
@@ -254,8 +293,9 @@
 
             if (mCallbacks.canHandleReceivedAssistDataLocked()) {
                 // Process any pending data and dispatch the new data as well
-                processPendingAssistData();
+                flushPendingAssistData();
                 dispatchAssistDataReceived(data);
+                tryDispatchRequestComplete();
             } else {
                 // Queue up the data for processing later
                 mAssistData.add(data);
@@ -273,8 +313,9 @@
 
             if (mCallbacks.canHandleReceivedAssistDataLocked()) {
                 // Process any pending data and dispatch the new data as well
-                processPendingAssistData();
+                flushPendingAssistData();
                 dispatchAssistScreenshotReceived(screenshot);
+                tryDispatchRequestComplete();
             } else {
                 // Queue up the data for processing later
                 mAssistScreenshot.add(screenshot);
@@ -298,6 +339,13 @@
         mCallbacks.onAssistScreenshotReceivedLocked(screenshot);
     }
 
+    private void tryDispatchRequestComplete() {
+        if (mPendingDataCount == 0 && mPendingScreenshotCount == 0 &&
+                mAssistData.isEmpty() && mAssistScreenshot.isEmpty()) {
+            mCallbacks.onAssistRequestCompleted();
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mPendingDataCount="); pw.println(mPendingDataCount);
         pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index b7bca1fb..ef94000 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -112,7 +112,7 @@
         }
     }
 
-    public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+    public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
         try {
             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
             keyStore.load(null);
@@ -120,6 +120,20 @@
             SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
             byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob);
             return decrypt(decryptionKey, intermediate);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("Failed to decrypt blob", e);
+        }
+    }
+
+    public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+        try {
+            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+            keyStore.load(null);
+
+            SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
+            byte[] intermediate = decrypt(decryptionKey, blob);
+            return decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
         } catch (CertificateException | IOException | BadPaddingException
                 | IllegalBlockSizeException
                 | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
@@ -150,9 +164,8 @@
             keyStore.setEntry(keyAlias,
                     new KeyStore.SecretKeyEntry(secretKey),
                     builder.build());
-            byte[] intermediate = encrypt(secretKey, data);
-            return encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
-
+            byte[] intermediate = encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, data);
+            return encrypt(secretKey, intermediate);
         } catch (CertificateException | IOException | BadPaddingException
                 | IllegalBlockSizeException
                 | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 9440f17..ca6c9e7 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -101,7 +101,8 @@
     private static final byte WEAVER_VERSION = 1;
     private static final int INVALID_WEAVER_SLOT = -1;
 
-    private static final byte SYNTHETIC_PASSWORD_VERSION = 1;
+    private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1;
+    private static final byte SYNTHETIC_PASSWORD_VERSION = 2;
     private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0;
     private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1;
 
@@ -792,6 +793,7 @@
         byte[] pwdToken = computePasswordToken(credential, pwd);
 
         final byte[] applicationId;
+        final long sid;
         int weaverSlot = loadWeaverSlot(handle, userId);
         if (weaverSlot != INVALID_WEAVER_SLOT) {
             // Weaver based user password
@@ -804,6 +806,7 @@
             if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
                 return result;
             }
+            sid = GateKeeper.INVALID_SECURE_USER_ID;
             applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload());
         } else {
             byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
@@ -836,12 +839,13 @@
                 result.gkResponse = VerifyCredentialResponse.ERROR;
                 return result;
             }
+            sid = sidFromPasswordHandle(pwd.passwordHandle);
             applicationId = transformUnderSecdiscardable(pwdToken,
                     loadSecdiscardable(handle, userId));
         }
 
         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
-                applicationId, userId);
+                applicationId, sid, userId);
 
         // Perform verifyChallenge to refresh auth tokens for GK if user password exists.
         result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
@@ -877,7 +881,7 @@
         }
         byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable);
         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED,
-                applicationId, userId);
+                applicationId, 0L, userId);
         if (result.authToken != null) {
             result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
             if (result.gkResponse == null) {
@@ -892,19 +896,26 @@
     }
 
     private AuthenticationToken unwrapSyntheticPasswordBlob(long handle, byte type,
-            byte[] applicationId, int userId) {
+            byte[] applicationId, long sid, int userId) {
         byte[] blob = loadState(SP_BLOB_NAME, handle, userId);
         if (blob == null) {
             return null;
         }
-        if (blob[0] != SYNTHETIC_PASSWORD_VERSION) {
+        final byte version = blob[0];
+        if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) {
             throw new RuntimeException("Unknown blob version");
         }
         if (blob[1] != type) {
             throw new RuntimeException("Invalid blob type");
         }
-        byte[] secret = decryptSPBlob(getHandleName(handle),
+        final byte[] secret;
+        if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+            secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle),
+                    Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+        } else {
+            secret = decryptSPBlob(getHandleName(handle),
                 Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+        }
         if (secret == null) {
             Log.e(TAG, "Fail to decrypt SP for user " + userId);
             return null;
@@ -919,6 +930,10 @@
         } else {
             result.syntheticPassword = new String(secret);
         }
+        if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+            Log.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
+            createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
+        }
         return result;
     }
 
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 365366a..d8726bf 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -149,6 +149,9 @@
         @Override
         public void binderDied() {
             // Clean up the state if the listener dies
+            if (mPinnedStackListener != null) {
+                mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
+            }
             mPinnedStackListener = null;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
index bec46db..ce88d84 100644
--- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
@@ -22,6 +22,7 @@
 import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
 import static android.graphics.Bitmap.Config.ARGB_8888;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -74,6 +75,8 @@
     private static final boolean CALLER_ASSIST_SCREENSHOT_ALLOWED = true;
     private static final boolean FETCH_DATA = true;
     private static final boolean FETCH_SCREENSHOTS = true;
+    private static final boolean ALLOW_FETCH_DATA = true;
+    private static final boolean ALLOW_FETCH_SCREENSHOTS = true;
 
     private static final int TEST_UID = 0;
     private static final String TEST_PACKAGE = "";
@@ -128,8 +131,7 @@
             mHandler.post(() -> {
                 try {
                     mGate.await(10, TimeUnit.SECONDS);
-                    mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1,
-                            ARGB_8888));
+                    mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1, ARGB_8888));
                 } catch (InterruptedException e) {
                     Log.e(TAG, "Failed to wait", e);
                 }
@@ -153,7 +155,7 @@
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         assertReceivedDataCount(5, 5, 1, 1);
     }
 
@@ -163,18 +165,18 @@
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(0), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         assertReceivedDataCount(0, 0, 0, 0);
     }
 
     @Test
-    public void testCurrentAppDisallow_expectNoCallbacks() throws Exception {
+    public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
         setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
-        assertReceivedDataCount(0, 0, 0, 0);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+        assertReceivedDataCount(0, 1, 0, 1);
     }
 
     @Test
@@ -184,7 +186,7 @@
 
         mCallbacks.canHandleReceivedData = false;
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         assertTrue(mDataRequester.getPendingDataCount() == 5);
         assertTrue(mDataRequester.getPendingScreenshotCount() == 1);
         mGate.countDown();
@@ -195,21 +197,32 @@
         assertTrue(mDataRequester.getPendingScreenshotCount() == 0);
         assertTrue(mCallbacks.receivedData.isEmpty());
         assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+        assertFalse(mCallbacks.requestCompleted);
 
         mCallbacks.canHandleReceivedData = true;
         mDataRequester.processPendingAssistData();
+        // Since we are posting the callback for the request-complete, flush the handler as well
+        mGate.countDown();
+        waitForIdle(mHandler);
         assertTrue(mCallbacks.receivedData.size() == 5);
         assertTrue(mCallbacks.receivedScreenshots.size() == 1);
+        assertTrue(mCallbacks.requestCompleted);
+
+        // Clear the state and ensure that we only process pending data once
+        mCallbacks.reset();
+        mDataRequester.processPendingAssistData();
+        assertTrue(mCallbacks.receivedData.isEmpty());
+        assertTrue(mCallbacks.receivedScreenshots.isEmpty());
     }
 
     @Test
-    public void testNoFetchData_expectNoCallbacks() throws Exception {
+    public void testNoFetchData_expectNoDataCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), !FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
-        assertReceivedDataCount(0, 0, 0, 0);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+        assertReceivedDataCount(0, 0, 0, 1);
     }
 
     @Test
@@ -218,9 +231,9 @@
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         // Expect a single null data when the appops is denied
-        assertReceivedDataCount(0, 1, 0, 0);
+        assertReceivedDataCount(0, 1, 0, 1);
     }
 
     @Test
@@ -231,9 +244,9 @@
                 anyBoolean(), anyBoolean());
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         // Expect a single null data when requestAssistContextExtras() fails
-        assertReceivedDataCount(0, 1, 0, 0);
+        assertReceivedDataCount(0, 1, 0, 1);
     }
 
     @Test
@@ -242,7 +255,7 @@
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, !FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         assertReceivedDataCount(5, 5, 0, 0);
     }
 
@@ -252,11 +265,35 @@
                 !CALLER_ASSIST_SCREENSHOT_ALLOWED);
 
         mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
-                TEST_UID, TEST_PACKAGE);
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
         // Expect a single null screenshot when the appops is denied
         assertReceivedDataCount(5, 5, 0, 1);
     }
 
+    @Test
+    public void testCanNotHandleReceivedData_expectNoCallbacks() throws Exception {
+        setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, !CALLER_ASSIST_STRUCTURE_ALLOWED,
+                !CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+        mCallbacks.canHandleReceivedData = false;
+        mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+                ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+        mGate.countDown();
+        waitForIdle(mHandler);
+        assertTrue(mCallbacks.receivedData.isEmpty());
+        assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+    }
+
+    @Test
+    public void testRequestDataNoneAllowed_expectNullCallbacks() throws Exception {
+        setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
+                CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+        mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+                !ALLOW_FETCH_DATA, !ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+        assertReceivedDataCount(0, 1, 0, 1);
+    }
+
     private void assertReceivedDataCount(int numPendingData, int numReceivedData,
             int numPendingScreenshots, int numReceivedScreenshots) throws Exception {
         assertTrue("Expected " + numPendingData + " pending data, got "
@@ -265,6 +302,7 @@
         assertTrue("Expected " + numPendingScreenshots + " pending screenshots, got "
                         + mDataRequester.getPendingScreenshotCount(),
                 mDataRequester.getPendingScreenshotCount() == numPendingScreenshots);
+        assertFalse("Expected request NOT completed", mCallbacks.requestCompleted);
         mGate.countDown();
         waitForIdle(mHandler);
         assertTrue("Expected " + numReceivedData + " data, received "
@@ -273,6 +311,7 @@
         assertTrue("Expected " + numReceivedScreenshots + " screenshots, received "
                         + mCallbacks.receivedScreenshots.size(),
                 mCallbacks.receivedScreenshots.size() == numReceivedScreenshots);
+        assertTrue("Expected request completed", mCallbacks.requestCompleted);
     }
 
     private List<IBinder> createActivityList(int size) {
@@ -292,12 +331,19 @@
         latch.await(2, TimeUnit.SECONDS);
     }
 
-    private static class Callbacks implements AssistDataRequesterCallbacks {
+    private class Callbacks implements AssistDataRequesterCallbacks {
 
         boolean canHandleReceivedData = true;
+        boolean requestCompleted = false;
         ArrayList<Bundle> receivedData = new ArrayList<>();
         ArrayList<Bitmap> receivedScreenshots = new ArrayList<>();
 
+        void reset() {
+            canHandleReceivedData = true;
+            receivedData.clear();
+            receivedScreenshots.clear();
+        }
+
         @Override
         public boolean canHandleReceivedAssistDataLocked() {
             return canHandleReceivedData;
@@ -312,5 +358,17 @@
         public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
             receivedScreenshots.add(screenshot);
         }
+
+        @Override
+        public void onAssistRequestCompleted() {
+            mHandler.post(() -> {
+                try {
+                    mGate.await(10, TimeUnit.SECONDS);
+                    requestCompleted = true;
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Failed to wait", e);
+                }
+            });
+        }
     }
 }
\ No newline at end of file
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 925219d..e0d9c73 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -198,7 +198,10 @@
             mShowArgs = args;
             mShowFlags = flags;
 
+            disabledContext |= getUserDisabledShowContextLocked();
             mAssistDataRequester.requestAssistData(topActivities,
+                    (flags & VoiceInteractionSession.SHOW_WITH_ASSIST) != 0,
+                    (flags & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0,
                     (disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
                     (disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
                     mCallingUid, mSessionComponentName.getPackageName());
@@ -215,6 +218,7 @@
                     mShowFlags = 0;
                 } catch (RemoteException e) {
                 }
+                mAssistDataRequester.processPendingAssistData();
             } else if (showCallback != null) {
                 mPendingShowCallbacks.add(showCallback);
             }
@@ -237,11 +241,16 @@
 
     @Override
     public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
+        // Return early if we have no session
+        if (mSession == null) {
+            return;
+        }
+
         if (data == null) {
             try {
                 mSession.handleAssist(null, null, null, 0, 0);
             } catch (RemoteException e) {
-                // Can't happen
+                // Ignore
             }
         } else {
             final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
@@ -267,17 +276,22 @@
                 mSession.handleAssist(assistData, structure, content, activityIndex,
                         activityCount);
             } catch (RemoteException e) {
-                // Can't happen
+                // Ignore
             }
         }
     }
 
     @Override
     public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
+        // Return early if we have no session
+        if (mSession == null) {
+            return;
+        }
+
         try {
             mSession.handleScreenshot(screenshot);
         } catch (RemoteException e) {
-            // Can't happen
+            // Ignore
         }
     }