From e55e544fef62d912de6fbb98c94eab3966980878 Mon Sep 17 00:00:00 2001 From: Song Hu Date: Thu, 22 Apr 2021 08:26:27 -0700 Subject: [PATCH] Query and surface Quick Share chip before screenshot image compress/export. Update chip intent, once image URL is available after compress/export. Test: test on local device Bug: 185423664 Change-Id: I2710a727d4fc4fabaa1404d965feaa0c97d502fc --- .../sysui/SystemUiDeviceConfigFlags.java | 6 ++ .../screenshot/SaveImageInBackgroundTask.java | 89 ++++++++++++++++++- .../screenshot/ScreenshotController.java | 83 +++++++++++++---- .../screenshot/ScreenshotSmartActions.java | 30 ++++--- .../systemui/screenshot/ScreenshotView.java | 43 ++++++++- ...creenshotNotificationSmartActionsTest.java | 11 ++- 6 files changed, 227 insertions(+), 35 deletions(-) diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 52801faf9c364..927c44f416280 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -81,6 +81,12 @@ public final class SystemUiDeviceConfigFlags { public static final String SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS = "screenshot_notification_smart_actions_timeout_ms"; + /** + * (int) Timeout value in ms to get Quick Share actions for screenshot notification. + */ + public static final String SCREENSHOT_NOTIFICATION_QUICK_SHARE_ACTIONS_TIMEOUT_MS = + "screenshot_notification_quick_share_actions_timeout_ms"; + // Flags related to Smart Suggestions - these are read in SmartReplyConstants. /** (boolean) Whether to enable smart suggestions in notifications. */ diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index 0106f43163900..b5e51c68b76ad 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -20,6 +20,8 @@ import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS; import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK; import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE; import static com.android.systemui.screenshot.LogConfig.logTag; +import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION; +import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS; import android.app.ActivityTaskManager; import android.app.Notification; @@ -74,6 +76,7 @@ class SaveImageInBackgroundTask extends AsyncTask { private final ScreenshotSmartActions mScreenshotSmartActions; private final ScreenshotController.SaveImageInBackgroundData mParams; private final ScreenshotController.SavedImageData mImageData; + private final ScreenshotController.QuickShareData mQuickShareData; private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider; private String mScreenshotId; @@ -90,6 +93,7 @@ class SaveImageInBackgroundTask extends AsyncTask { mContext = context; mScreenshotSmartActions = screenshotSmartActions; mImageData = new ScreenshotController.SavedImageData(); + mQuickShareData = new ScreenshotController.QuickShareData(); mSharedElementTransition = sharedElementTransition; mImageExporter = exporter; @@ -127,6 +131,13 @@ class SaveImageInBackgroundTask extends AsyncTask { Bitmap image = mParams.image; mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, requestId); try { + if (mSmartActionsEnabled && mParams.mQuickShareActionsReadyListener != null) { + // Since Quick Share target recommendation does not rely on image URL, it is + // queried and surfaced before image compress/export. Action intent would not be + // used, because it does not contain image URL. + queryQuickShareAction(image, user); + } + // Call synchronously here since already on a background thread. ListenableFuture future = mImageExporter.export(Runnable::run, requestId, image); @@ -136,7 +147,7 @@ class SaveImageInBackgroundTask extends AsyncTask { CompletableFuture> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture( - mScreenshotId, uri, image, mSmartActionsProvider, + mScreenshotId, uri, image, mSmartActionsProvider, REGULAR_SMART_ACTIONS, mSmartActionsEnabled, user); List smartActions = new ArrayList<>(); @@ -148,7 +159,7 @@ class SaveImageInBackgroundTask extends AsyncTask { smartActions.addAll(buildSmartActions( mScreenshotSmartActions.getSmartActions( mScreenshotId, smartActionsFuture, timeoutMs, - mSmartActionsProvider), + mSmartActionsProvider, REGULAR_SMART_ACTIONS), mContext)); } @@ -157,6 +168,8 @@ class SaveImageInBackgroundTask extends AsyncTask { mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri); mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri); mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri); + mImageData.quickShareAction = createQuickShareAction(mContext, + mQuickShareData.quickShareAction, uri); mParams.mActionsReadyListener.onActionsReady(mImageData); if (DEBUG_CALLBACK) { @@ -173,6 +186,7 @@ class SaveImageInBackgroundTask extends AsyncTask { } mParams.clearImage(); mImageData.reset(); + mQuickShareData.reset(); mParams.mActionsReadyListener.onActionsReady(mImageData); if (DEBUG_CALLBACK) { Log.d(TAG, "Calling (Consumer) finisher.accept(null)"); @@ -197,6 +211,7 @@ class SaveImageInBackgroundTask extends AsyncTask { // params. The finisher is expected to always be called back, so just use the baked-in // params from the ctor in any case. mImageData.reset(); + mQuickShareData.reset(); mParams.mActionsReadyListener.onActionsReady(mImageData); if (DEBUG_CALLBACK) { Log.d(TAG, "onCancelled, calling (Consumer) finisher.accept(null)"); @@ -389,4 +404,74 @@ class SaveImageInBackgroundTask extends AsyncTask { .putExtra(ScreenshotController.EXTRA_ID, screenshotId) .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled); } + + /** + * Populate image uri into intent of Quick Share action. + */ + @VisibleForTesting + private Notification.Action createQuickShareAction(Context context, Notification.Action action, + Uri uri) { + if (action == null) { + return null; + } + // Populate image URI into Quick Share chip intent + Intent sharingIntent = action.actionIntent.getIntent(); + sharingIntent.setType("image/png"); + sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); + String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); + String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); + sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + // Include URI in ClipData also, so that grantPermission picks it up. + // We don't use setData here because some apps interpret this as "to:". + ClipData clipdata = new ClipData(new ClipDescription("content", + new String[]{"image/png"}), + new ClipData.Item(uri)); + sharingIntent.setClipData(clipdata); + sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + PendingIntent updatedPendingIntent = PendingIntent.getActivity( + context, 0, sharingIntent, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); + + // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver} + // for logging smart actions. + Bundle extras = action.getExtras(); + String actionType = extras.getString( + ScreenshotNotificationSmartActionsProvider.ACTION_TYPE, + ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE); + Intent intent = new Intent(context, SmartActionsReceiver.class) + .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled); + PendingIntent broadcastIntent = PendingIntent.getBroadcast(context, + mRandom.nextInt(), + intent, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); + return new Notification.Action.Builder(action.getIcon(), action.title, + broadcastIntent).setContextual(true).addExtras(extras).build(); + } + + /** + * Query and surface Quick Share chip if it is available. Action intent would not be used, + * because it does not contain image URL which would be populated in {@link + * #createQuickShareAction(Context, Notification.Action, Uri)} + */ + private void queryQuickShareAction(Bitmap image, UserHandle user) { + CompletableFuture> quickShareActionsFuture = + mScreenshotSmartActions.getSmartActionsFuture( + mScreenshotId, null, image, mSmartActionsProvider, + QUICK_SHARE_ACTION, + mSmartActionsEnabled, user); + int timeoutMs = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.SCREENSHOT_NOTIFICATION_QUICK_SHARE_ACTIONS_TIMEOUT_MS, + 500); + List quickShareActions = + mScreenshotSmartActions.getSmartActions( + mScreenshotId, quickShareActionsFuture, timeoutMs, + mSmartActionsProvider, QUICK_SHARE_ACTION); + if (!quickShareActions.isEmpty()) { + mQuickShareData.quickShareAction = quickShareActions.get(0); + mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index c1ae29230e616..1fe8cbf3feb42 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -25,7 +25,6 @@ import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM; import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK; import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS; import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT; -import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL; import static com.android.systemui.screenshot.LogConfig.DEBUG_UI; import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW; import static com.android.systemui.screenshot.LogConfig.logTag; @@ -118,6 +117,7 @@ public class ScreenshotController { public Bitmap image; public Consumer finisher; public ScreenshotController.ActionsReadyListener mActionsReadyListener; + public ScreenshotController.QuickShareActionReadyListener mQuickShareActionsReadyListener; void clearImage() { image = null; @@ -133,6 +133,7 @@ public class ScreenshotController { public Supplier editTransition; public Notification.Action deleteAction; public List smartActions; + public Notification.Action quickShareAction; /** * POD for shared element transition. @@ -152,6 +153,21 @@ public class ScreenshotController { editTransition = null; deleteAction = null; smartActions = null; + quickShareAction = null; + } + } + + /** + * Structure returned by the QueryQuickShareInBackgroundTask + */ + static class QuickShareData { + public Notification.Action quickShareAction; + + /** + * Used to reset the return data on error + */ + public void reset() { + quickShareAction = null; } } @@ -159,6 +175,10 @@ public class ScreenshotController { void onActionsReady(ScreenshotController.SavedImageData imageData); } + interface QuickShareActionReadyListener { + void onActionsReady(ScreenshotController.QuickShareData quickShareData); + } + // These strings are used for communicating the action invoked to // ScreenshotNotificationSmartActionsProvider. static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type"; @@ -520,7 +540,8 @@ public class ScreenshotController { mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); - saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady); + saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady, + this::showUiOnQuickShareActionReady); // The window is focusable by default setWindowFocusable(true); @@ -655,20 +676,21 @@ public class ScreenshotController { saveScreenshotInWorkerThread( /* onComplete */ finisher, /* actionsReadyListener */ imageData -> { - if (DEBUG_CALLBACK) { - Log.d(TAG, "returning URI to finisher (Consumer): " + imageData.uri); - } - finisher.accept(imageData.uri); - if (imageData.uri == null) { - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED); - mNotificationsController.notifyScreenshotError( - R.string.screenshot_failed_to_save_text); - } else { - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED); - mScreenshotHandler.post(() -> Toast.makeText(mContext, - R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show()); - } - }); + if (DEBUG_CALLBACK) { + Log.d(TAG, "returning URI to finisher (Consumer): " + imageData.uri); + } + finisher.accept(imageData.uri); + if (imageData.uri == null) { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED); + mNotificationsController.notifyScreenshotError( + R.string.screenshot_failed_to_save_text); + } else { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED); + mScreenshotHandler.post(() -> Toast.makeText(mContext, + R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show()); + } + }, + null); } /** @@ -709,12 +731,15 @@ public class ScreenshotController { * Creates a new worker thread and saves the screenshot to the media store. */ private void saveScreenshotInWorkerThread(Consumer finisher, - @Nullable ScreenshotController.ActionsReadyListener actionsReadyListener) { + @Nullable ScreenshotController.ActionsReadyListener actionsReadyListener, + @Nullable ScreenshotController.QuickShareActionReadyListener + quickShareActionsReadyListener) { ScreenshotController.SaveImageInBackgroundData data = new ScreenshotController.SaveImageInBackgroundData(); data.image = mScreenBitmap; data.finisher = finisher; data.mActionsReadyListener = actionsReadyListener; + data.mQuickShareActionsReadyListener = quickShareActionsReadyListener; if (mSaveInBgTask != null) { // just log success/failure for the pre-existing screenshot @@ -776,6 +801,30 @@ public class ScreenshotController { } } + /** + * Sets up the action shade and its entrance animation, once we get the Quick Share action data. + */ + private void showUiOnQuickShareActionReady(ScreenshotController.QuickShareData quickShareData) { + if (DEBUG_UI) { + Log.d(TAG, "Showing UI for Quick Share action"); + } + if (quickShareData.quickShareAction != null) { + mScreenshotHandler.post(() -> { + if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) { + mScreenshotAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mScreenshotView.addQuickShareChip(quickShareData.quickShareAction); + } + }); + } else { + mScreenshotView.addQuickShareChip(quickShareData.quickShareAction); + } + }); + } + } + /** * Supplies the necessary bits for the shared element transition to share sheet. * Note that once supplied, the action intent to share must be sent immediately after. diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java index 9bd7923016f2b..99238cd2c2676 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java @@ -60,11 +60,14 @@ public class ScreenshotSmartActions { CompletableFuture> getSmartActionsFuture( String screenshotId, Uri screenshotUri, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, + ScreenshotSmartActionType actionType, boolean smartActionsEnabled, UserHandle userHandle) { if (DEBUG_ACTIONS) { - Log.d(TAG, String.format("getSmartActionsFuture id=%s, uri=%s, provider=%s, " - + "smartActionsEnabled=%b, userHandle=%s", screenshotId, screenshotUri, - smartActionsProvider.getClass(), smartActionsEnabled, userHandle)); + Log.d(TAG, String.format( + "getSmartActionsFuture id=%s, uri=%s, provider=%s, actionType=%s, " + + "smartActionsEnabled=%b, userHandle=%s", + screenshotId, screenshotUri, smartActionsProvider.getClass(), actionType, + smartActionsEnabled, userHandle)); } if (!smartActionsEnabled) { if (DEBUG_ACTIONS) { @@ -89,7 +92,7 @@ public class ScreenshotSmartActions { ? runningTask.topActivity : new ComponentName("", ""); smartActionsFuture = smartActionsProvider.getActions(screenshotId, screenshotUri, image, - componentName, ScreenshotSmartActionType.REGULAR_SMART_ACTIONS, userHandle); + componentName, actionType, userHandle); } catch (Throwable e) { long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList()); @@ -107,19 +110,21 @@ public class ScreenshotSmartActions { @VisibleForTesting List getSmartActions(String screenshotId, CompletableFuture> smartActionsFuture, int timeoutMs, - ScreenshotNotificationSmartActionsProvider smartActionsProvider) { + ScreenshotNotificationSmartActionsProvider smartActionsProvider, + ScreenshotSmartActionType actionType) { long startTimeMs = SystemClock.uptimeMillis(); if (DEBUG_ACTIONS) { - Log.d(TAG, String.format("getSmartActions id=%s, timeoutMs=%d, provider=%s", - screenshotId, timeoutMs, smartActionsProvider.getClass())); + Log.d(TAG, + String.format("getSmartActions id=%s, timeoutMs=%d, actionType=%s, provider=%s", + screenshotId, timeoutMs, actionType, smartActionsProvider.getClass())); } try { List actions = smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS); long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; if (DEBUG_ACTIONS) { - Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms", - actions.size(), waitTimeMs)); + Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms, actionType=%s", + actions.size(), waitTimeMs, actionType)); } notifyScreenshotOp(screenshotId, smartActionsProvider, ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, @@ -129,8 +134,9 @@ public class ScreenshotSmartActions { } catch (Throwable e) { long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; if (DEBUG_ACTIONS) { - Log.e(TAG, String.format("Error getting smart actions. Wait time: %d ms", - waitTimeMs), e); + Log.e(TAG, String.format( + "Error getting smart actions. Wait time: %d ms, actionType=%s", + waitTimeMs, actionType), e); } ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status = (e instanceof TimeoutException) @@ -165,7 +171,7 @@ public class ScreenshotSmartActions { SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( context, THREAD_POOL_EXECUTOR, new Handler()); if (DEBUG_ACTIONS) { - Log.e(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b", + Log.d(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b", provider.getClass(), action, screenshotId, isSmartAction)); } provider.notifyAction(screenshotId, action, isSmartAction); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index 5c650ad3982e5..2233dd8f5001e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -137,6 +137,7 @@ public class ScreenshotView extends FrameLayout implements private ScreenshotActionChip mShareChip; private ScreenshotActionChip mEditChip; private ScreenshotActionChip mScrollChip; + private ScreenshotActionChip mQuickShareChip; private UiEventLogger mUiEventLogger; private ScreenshotViewCallback mCallbacks; @@ -149,7 +150,8 @@ public class ScreenshotView extends FrameLayout implements private enum PendingInteraction { PREVIEW, EDIT, - SHARE + SHARE, + QUICK_SHARE } public ScreenshotView(Context context) { @@ -481,6 +483,9 @@ public class ScreenshotView extends FrameLayout implements mShareChip.setOnClickListener(v -> { mShareChip.setIsPending(true); mEditChip.setIsPending(false); + if (mQuickShareChip != null) { + mQuickShareChip.setIsPending(false); + } mPendingInteraction = PendingInteraction.SHARE; }); chips.add(mShareChip); @@ -490,6 +495,9 @@ public class ScreenshotView extends FrameLayout implements mEditChip.setOnClickListener(v -> { mEditChip.setIsPending(true); mShareChip.setIsPending(false); + if (mQuickShareChip != null) { + mQuickShareChip.setIsPending(false); + } mPendingInteraction = PendingInteraction.EDIT; }); chips.add(mEditChip); @@ -497,6 +505,9 @@ public class ScreenshotView extends FrameLayout implements mScreenshotPreview.setOnClickListener(v -> { mShareChip.setIsPending(false); mEditChip.setIsPending(false); + if (mQuickShareChip != null) { + mQuickShareChip.setIsPending(false); + } mPendingInteraction = PendingInteraction.PREVIEW; }); @@ -558,6 +569,13 @@ public class ScreenshotView extends FrameLayout implements startSharedTransition( imageData.editTransition.get()); }); + if (mQuickShareChip != null) { + mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent, + () -> { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED); + animateDismissal(); + }); + } if (mPendingInteraction != null) { switch (mPendingInteraction) { @@ -570,6 +588,9 @@ public class ScreenshotView extends FrameLayout implements case EDIT: mEditChip.callOnClick(); break; + case QUICK_SHARE: + mQuickShareChip.callOnClick(); + break; } } else { LayoutInflater inflater = LayoutInflater.from(mContext); @@ -591,6 +612,25 @@ public class ScreenshotView extends FrameLayout implements } } + void addQuickShareChip(Notification.Action quickShareAction) { + if (mPendingInteraction == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + mQuickShareChip = (ScreenshotActionChip) inflater.inflate( + R.layout.global_screenshot_action_chip, mActionsView, false); + mQuickShareChip.setText(quickShareAction.title); + mQuickShareChip.setIcon(quickShareAction.getIcon(), false); + mQuickShareChip.setOnClickListener(v -> { + mShareChip.setIsPending(false); + mEditChip.setIsPending(false); + mQuickShareChip.setIsPending(true); + mPendingInteraction = PendingInteraction.QUICK_SHARE; + }); + mQuickShareChip.setAlpha(1); + mActionsView.addView(mQuickShareChip); + mSmartChips.add(mQuickShareChip); + } + } + boolean isDismissing() { return (mDismissAnimation != null && mDismissAnimation.isRunning()); } @@ -676,6 +716,7 @@ public class ScreenshotView extends FrameLayout implements mActionsView.removeView(chip); } mSmartChips.clear(); + mQuickShareChip = null; setAlpha(1); mDismissButton.setTranslationY(0); mActionsContainer.setTranslationY(0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 8c7d762b23072..3d658ec8e811d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -16,6 +16,8 @@ package com.android.systemui.screenshot; +import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -87,6 +89,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { CompletableFuture> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://authority/data"), bitmap, smartActionsProvider, + REGULAR_SMART_ACTIONS, true, UserHandle.of(UserHandle.myUserId())); assertNotNull(smartActionsFuture); List smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); @@ -104,7 +107,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS)).thenThrow( RuntimeException.class); List actions = mScreenshotSmartActions.getSmartActions( - "", smartActionsFuture, timeoutMs, mSmartActionsProvider); + "", smartActionsFuture, timeoutMs, mSmartActionsProvider, REGULAR_SMART_ACTIONS); assertEquals(Collections.emptyList(), actions); } @@ -127,6 +130,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { CompletableFuture> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, + REGULAR_SMART_ACTIONS, true, UserHandle.of(UserHandle.myUserId())); verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), any(), any()); assertNotNull(smartActionsFuture); @@ -140,7 +144,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); mScreenshotSmartActions.getSmartActionsFuture( - "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, true, + "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, + REGULAR_SMART_ACTIONS, true, UserHandle.of(UserHandle.myUserId())); verify(mSmartActionsProvider, times(1)).getActions( any(), any(), any(), any(), any(), any()); @@ -157,7 +162,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { mContext, null, mHandler); CompletableFuture> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture("", null, bitmap, - actionsProvider, + actionsProvider, REGULAR_SMART_ACTIONS, true, UserHandle.of(UserHandle.myUserId())); assertNotNull(smartActionsFuture); List smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS);