Merge "[DO NOT MERGE] Update quickshare intent rather than recreating" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4ef79c3ff3
@@ -89,7 +89,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
SaveImageInBackgroundTask(Context context, ImageExporter exporter,
|
SaveImageInBackgroundTask(Context context, ImageExporter exporter,
|
||||||
ScreenshotSmartActions screenshotSmartActions,
|
ScreenshotSmartActions screenshotSmartActions,
|
||||||
ScreenshotController.SaveImageInBackgroundData data,
|
ScreenshotController.SaveImageInBackgroundData data,
|
||||||
Supplier<ActionTransition> sharedElementTransition) {
|
Supplier<ActionTransition> sharedElementTransition,
|
||||||
|
boolean smartActionsEnabled) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mScreenshotSmartActions = screenshotSmartActions;
|
mScreenshotSmartActions = screenshotSmartActions;
|
||||||
mImageData = new ScreenshotController.SavedImageData();
|
mImageData = new ScreenshotController.SavedImageData();
|
||||||
@@ -101,8 +102,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
mParams = data;
|
mParams = data;
|
||||||
|
|
||||||
// Initialize screenshot notification smart actions provider.
|
// Initialize screenshot notification smart actions provider.
|
||||||
mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
|
mSmartActionsEnabled = smartActionsEnabled;
|
||||||
SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
|
|
||||||
if (mSmartActionsEnabled) {
|
if (mSmartActionsEnabled) {
|
||||||
mSmartActionsProvider =
|
mSmartActionsProvider =
|
||||||
SystemUIFactory.getInstance()
|
SystemUIFactory.getInstance()
|
||||||
@@ -135,7 +135,12 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
// Since Quick Share target recommendation does not rely on image URL, it is
|
// 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
|
// queried and surfaced before image compress/export. Action intent would not be
|
||||||
// used, because it does not contain image URL.
|
// used, because it does not contain image URL.
|
||||||
queryQuickShareAction(image, user);
|
Notification.Action quickShare =
|
||||||
|
queryQuickShareAction(mScreenshotId, image, user, null);
|
||||||
|
if (quickShare != null) {
|
||||||
|
mQuickShareData.quickShareAction = quickShare;
|
||||||
|
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call synchronously here since already on a background thread.
|
// Call synchronously here since already on a background thread.
|
||||||
@@ -168,8 +173,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
|
mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
|
||||||
mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
|
mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
|
||||||
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
|
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
|
||||||
mImageData.quickShareAction = createQuickShareAction(mContext,
|
mImageData.quickShareAction = createQuickShareAction(
|
||||||
mQuickShareData.quickShareAction, uri);
|
mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
|
||||||
|
user);
|
||||||
|
|
||||||
mParams.mActionsReadyListener.onActionsReady(mImageData);
|
mParams.mActionsReadyListener.onActionsReady(mImageData);
|
||||||
if (DEBUG_CALLBACK) {
|
if (DEBUG_CALLBACK) {
|
||||||
@@ -407,60 +413,73 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate image uri into intent of Quick Share action.
|
* Wrap the quickshare intent and populate the fillin intent with the URI
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
private Notification.Action createQuickShareAction(Context context, Notification.Action action,
|
Notification.Action createQuickShareAction(
|
||||||
Uri uri) {
|
Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
|
||||||
if (action == null) {
|
Bitmap image, UserHandle user) {
|
||||||
|
if (quickShare == null) {
|
||||||
return null;
|
return null;
|
||||||
|
} else if (quickShare.actionIntent.isImmutable()) {
|
||||||
|
Notification.Action quickShareWithUri =
|
||||||
|
queryQuickShareAction(screenshotId, image, user, uri);
|
||||||
|
if (quickShareWithUri == null
|
||||||
|
|| !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
quickShare = quickShareWithUri;
|
||||||
}
|
}
|
||||||
// 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}
|
Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
|
||||||
// for logging smart actions.
|
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
|
||||||
Bundle extras = action.getExtras();
|
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
|
||||||
|
createFillInIntent(uri, imageTime))
|
||||||
|
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||||
|
Bundle extras = quickShare.getExtras();
|
||||||
String actionType = extras.getString(
|
String actionType = extras.getString(
|
||||||
ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
|
ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
|
||||||
ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
|
ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
|
||||||
Intent intent = new Intent(context, SmartActionsReceiver.class)
|
addIntentExtras(screenshotId, wrappedIntent, actionType, mSmartActionsEnabled);
|
||||||
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
|
PendingIntent broadcastIntent =
|
||||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
|
||||||
addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
|
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||||
PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
|
return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
|
||||||
mRandom.nextInt(),
|
broadcastIntent)
|
||||||
intent,
|
.setContextual(true)
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
.addExtras(extras)
|
||||||
return new Notification.Action.Builder(action.getIcon(), action.title,
|
.build();
|
||||||
broadcastIntent).setContextual(true).addExtras(extras).build();
|
}
|
||||||
|
|
||||||
|
private Intent createFillInIntent(Uri uri, long imageTime) {
|
||||||
|
Intent fillIn = new Intent();
|
||||||
|
fillIn.setType("image/png");
|
||||||
|
fillIn.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
|
||||||
|
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
|
||||||
|
fillIn.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));
|
||||||
|
fillIn.setClipData(clipData);
|
||||||
|
fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
return fillIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query and surface Quick Share chip if it is available. Action intent would not be used,
|
* 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
|
* because it does not contain image URL which would be populated in {@link
|
||||||
* #createQuickShareAction(Context, Notification.Action, Uri)}
|
* #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
|
||||||
*/
|
*/
|
||||||
private void queryQuickShareAction(Bitmap image, UserHandle user) {
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Notification.Action queryQuickShareAction(
|
||||||
|
String screenshotId, Bitmap image, UserHandle user, Uri uri) {
|
||||||
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
|
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
|
||||||
mScreenshotSmartActions.getSmartActionsFuture(
|
mScreenshotSmartActions.getSmartActionsFuture(
|
||||||
mScreenshotId, null, image, mSmartActionsProvider,
|
screenshotId, uri, image, mSmartActionsProvider, QUICK_SHARE_ACTION,
|
||||||
QUICK_SHARE_ACTION,
|
|
||||||
mSmartActionsEnabled, user);
|
mSmartActionsEnabled, user);
|
||||||
int timeoutMs = DeviceConfig.getInt(
|
int timeoutMs = DeviceConfig.getInt(
|
||||||
DeviceConfig.NAMESPACE_SYSTEMUI,
|
DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
@@ -468,11 +487,11 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
|||||||
500);
|
500);
|
||||||
List<Notification.Action> quickShareActions =
|
List<Notification.Action> quickShareActions =
|
||||||
mScreenshotSmartActions.getSmartActions(
|
mScreenshotSmartActions.getSmartActions(
|
||||||
mScreenshotId, quickShareActionsFuture, timeoutMs,
|
screenshotId, quickShareActionsFuture, timeoutMs,
|
||||||
mSmartActionsProvider, QUICK_SHARE_ACTION);
|
mSmartActionsProvider, QUICK_SHARE_ACTION);
|
||||||
if (!quickShareActions.isEmpty()) {
|
if (!quickShareActions.isEmpty()) {
|
||||||
mQuickShareData.quickShareAction = quickShareActions.get(0);
|
return quickShareActions.get(0);
|
||||||
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import android.os.IBinder;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -82,6 +83,7 @@ import android.widget.Toast;
|
|||||||
import android.window.WindowContext;
|
import android.window.WindowContext;
|
||||||
|
|
||||||
import com.android.internal.app.ChooserActivity;
|
import com.android.internal.app.ChooserActivity;
|
||||||
|
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.internal.policy.PhoneWindow;
|
import com.android.internal.policy.PhoneWindow;
|
||||||
import com.android.settingslib.applications.InterestingConfigChanges;
|
import com.android.settingslib.applications.InterestingConfigChanges;
|
||||||
@@ -226,6 +228,7 @@ public class ScreenshotController {
|
|||||||
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
|
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
|
||||||
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
|
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
|
||||||
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
|
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
|
||||||
|
static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
|
||||||
|
|
||||||
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
|
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
|
||||||
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
|
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
|
||||||
@@ -851,8 +854,11 @@ public class ScreenshotController {
|
|||||||
mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
|
mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean smartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
|
SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
|
||||||
|
|
||||||
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
|
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
|
||||||
mScreenshotSmartActions, data, getActionTransitionSupplier());
|
mScreenshotSmartActions, data, getActionTransitionSupplier(), smartActionsEnabled);
|
||||||
mSaveInBgTask.execute();
|
mSaveInBgTask.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.systemui.screenshot;
|
|||||||
|
|
||||||
import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
|
import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
|
||||||
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
|
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
|
||||||
|
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT_FILLIN;
|
||||||
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
|
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
|
||||||
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;
|
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ public class SmartActionsReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
|
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
|
||||||
|
Intent fillIn = intent.getParcelableExtra(EXTRA_ACTION_INTENT_FILLIN);
|
||||||
String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
|
String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
|
||||||
if (DEBUG_ACTIONS) {
|
if (DEBUG_ACTIONS) {
|
||||||
Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
|
Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
|
||||||
@@ -54,7 +56,7 @@ public class SmartActionsReceiver extends BroadcastReceiver {
|
|||||||
ActivityOptions opts = ActivityOptions.makeBasic();
|
ActivityOptions opts = ActivityOptions.makeBasic();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pendingIntent.send(context, 0, null, null, null, null, opts.toBundle());
|
pendingIntent.send(context, 0, fillIn, null, null, null, opts.toBundle());
|
||||||
} catch (PendingIntent.CanceledException e) {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
Log.e(TAG, "Pending intent canceled", e);
|
Log.e(TAG, "Pending intent canceled", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.screenshot
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.UserHandle
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.screenshot.ScreenshotController.SaveImageInBackgroundData
|
||||||
|
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.function.Supplier
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mockito
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
class SaveImageInBackgroundTaskTest : SysuiTestCase() {
|
||||||
|
private val imageExporter = mock<ImageExporter>()
|
||||||
|
private val smartActions = mock<ScreenshotSmartActions>()
|
||||||
|
private val saveImageData = SaveImageInBackgroundData()
|
||||||
|
private val sharedTransitionSupplier =
|
||||||
|
mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>()
|
||||||
|
private val testScreenshotId: String = "testScreenshotId"
|
||||||
|
private val testBitmap = mock<Bitmap>()
|
||||||
|
private val testUser = UserHandle.getUserHandleForUid(0)
|
||||||
|
private val testIcon = mock<Icon>()
|
||||||
|
private val testImageTime = 1234.toLong()
|
||||||
|
|
||||||
|
private val smartActionsUriFuture = mock<CompletableFuture<List<Notification.Action>>>()
|
||||||
|
private val smartActionsFuture = mock<CompletableFuture<List<Notification.Action>>>()
|
||||||
|
|
||||||
|
private val testUri: Uri = Uri.parse("testUri")
|
||||||
|
private val intent =
|
||||||
|
Intent(Intent.ACTION_SEND)
|
||||||
|
.setComponent(
|
||||||
|
ComponentName.unflattenFromString(
|
||||||
|
"com.google.android.test/com.google.android.test.TestActivity"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private val immutablePendingIntent =
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
mContext,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
private val mutablePendingIntent =
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
mContext,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
|
)
|
||||||
|
|
||||||
|
private val saveImageTask =
|
||||||
|
SaveImageInBackgroundTask(
|
||||||
|
mContext,
|
||||||
|
imageExporter,
|
||||||
|
smartActions,
|
||||||
|
saveImageData,
|
||||||
|
sharedTransitionSupplier,
|
||||||
|
false, // forces a no-op implementation; we're mocking out the behavior anyway
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActionsFuture(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.any(Uri::class.java),
|
||||||
|
Mockito.eq(testBitmap),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.any(ScreenshotSmartActionType::class.java),
|
||||||
|
Mockito.any(Boolean::class.java),
|
||||||
|
Mockito.eq(testUser)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(smartActionsUriFuture)
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActionsFuture(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(null),
|
||||||
|
Mockito.eq(testBitmap),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.any(ScreenshotSmartActionType::class.java),
|
||||||
|
Mockito.any(Boolean::class.java),
|
||||||
|
Mockito.eq(testUser)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(smartActionsFuture)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testQueryQuickShare_noAction() {
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActions(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(smartActionsFuture),
|
||||||
|
Mockito.any(Int::class.java),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(ArrayList<Notification.Action>())
|
||||||
|
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)
|
||||||
|
|
||||||
|
assertNull(quickShareAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testQueryQuickShare_withActions() {
|
||||||
|
val actions = ArrayList<Notification.Action>()
|
||||||
|
actions.add(constructAction("Action One", mutablePendingIntent))
|
||||||
|
actions.add(constructAction("Action Two", mutablePendingIntent))
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActions(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(smartActionsUriFuture),
|
||||||
|
Mockito.any(Int::class.java),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(actions)
|
||||||
|
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)!!
|
||||||
|
|
||||||
|
assertEquals("Action One", quickShareAction.title)
|
||||||
|
assertEquals(mutablePendingIntent, quickShareAction.actionIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCreateQuickShareAction_originalWasNull_returnsNull() {
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.createQuickShareAction(
|
||||||
|
null,
|
||||||
|
testScreenshotId,
|
||||||
|
testUri,
|
||||||
|
testImageTime,
|
||||||
|
testBitmap,
|
||||||
|
testUser
|
||||||
|
)
|
||||||
|
|
||||||
|
assertNull(quickShareAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCreateQuickShareAction_immutableIntentDifferentAction_returnsNull() {
|
||||||
|
val actions = ArrayList<Notification.Action>()
|
||||||
|
actions.add(constructAction("New Test Action", immutablePendingIntent))
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActions(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(smartActionsUriFuture),
|
||||||
|
Mockito.any(Int::class.java),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(actions)
|
||||||
|
val origAction = constructAction("Old Test Action", immutablePendingIntent)
|
||||||
|
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.createQuickShareAction(
|
||||||
|
origAction,
|
||||||
|
testScreenshotId,
|
||||||
|
testUri,
|
||||||
|
testImageTime,
|
||||||
|
testBitmap,
|
||||||
|
testUser,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertNull(quickShareAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCreateQuickShareAction_mutableIntent_returnsSafeIntent() {
|
||||||
|
val actions = ArrayList<Notification.Action>()
|
||||||
|
val action = constructAction("Action One", mutablePendingIntent)
|
||||||
|
actions.add(action)
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActions(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(smartActionsUriFuture),
|
||||||
|
Mockito.any(Int::class.java),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(actions)
|
||||||
|
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.createQuickShareAction(
|
||||||
|
constructAction("Test Action", mutablePendingIntent),
|
||||||
|
testScreenshotId,
|
||||||
|
testUri,
|
||||||
|
testImageTime,
|
||||||
|
testBitmap,
|
||||||
|
testUser
|
||||||
|
)
|
||||||
|
val quickSharePendingIntent : PendingIntent =
|
||||||
|
quickShareAction.actionIntent.intent.extras!!.getParcelable(
|
||||||
|
ScreenshotController.EXTRA_ACTION_INTENT)!!
|
||||||
|
|
||||||
|
assertEquals("Test Action", quickShareAction.title)
|
||||||
|
assertEquals(mutablePendingIntent, quickSharePendingIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCreateQuickShareAction_immutableIntent_returnsSafeIntent() {
|
||||||
|
val actions = ArrayList<Notification.Action>()
|
||||||
|
val action = constructAction("Test Action", immutablePendingIntent)
|
||||||
|
actions.add(action)
|
||||||
|
Mockito.`when`(
|
||||||
|
smartActions.getSmartActions(
|
||||||
|
Mockito.eq(testScreenshotId),
|
||||||
|
Mockito.eq(smartActionsUriFuture),
|
||||||
|
Mockito.any(Int::class.java),
|
||||||
|
Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
|
||||||
|
Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(actions)
|
||||||
|
|
||||||
|
val quickShareAction =
|
||||||
|
saveImageTask.createQuickShareAction(
|
||||||
|
constructAction("Test Action", immutablePendingIntent),
|
||||||
|
testScreenshotId,
|
||||||
|
testUri,
|
||||||
|
testImageTime,
|
||||||
|
testBitmap,
|
||||||
|
testUser,
|
||||||
|
)!!
|
||||||
|
val quickSharePendingIntent : PendingIntent =
|
||||||
|
quickShareAction.actionIntent.intent.extras!!.getParcelable(
|
||||||
|
ScreenshotController.EXTRA_ACTION_INTENT)!!
|
||||||
|
|
||||||
|
assertEquals("Test Action", quickShareAction.title)
|
||||||
|
assertEquals(immutablePendingIntent, quickSharePendingIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun constructAction(title: String, intent: PendingIntent): Notification.Action {
|
||||||
|
return Notification.Action.Builder(testIcon, title, intent).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T =
|
||||||
|
Mockito.mock(T::class.java).apply(apply)
|
||||||
|
}
|
||||||
@@ -183,7 +183,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
|||||||
data.mActionsReadyListener = null;
|
data.mActionsReadyListener = null;
|
||||||
SaveImageInBackgroundTask task =
|
SaveImageInBackgroundTask task =
|
||||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||||
ActionTransition::new);
|
ActionTransition::new, false);
|
||||||
|
|
||||||
Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
|
Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
|
||||||
Uri.parse("Screenshot_123.png")).get().action;
|
Uri.parse("Screenshot_123.png")).get().action;
|
||||||
@@ -211,7 +211,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
|||||||
data.mActionsReadyListener = null;
|
data.mActionsReadyListener = null;
|
||||||
SaveImageInBackgroundTask task =
|
SaveImageInBackgroundTask task =
|
||||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||||
ActionTransition::new);
|
ActionTransition::new, false);
|
||||||
|
|
||||||
Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
|
Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
|
||||||
Uri.parse("Screenshot_123.png")).get().action;
|
Uri.parse("Screenshot_123.png")).get().action;
|
||||||
@@ -239,7 +239,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
|||||||
data.mActionsReadyListener = null;
|
data.mActionsReadyListener = null;
|
||||||
SaveImageInBackgroundTask task =
|
SaveImageInBackgroundTask task =
|
||||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||||
ActionTransition::new);
|
ActionTransition::new, false);
|
||||||
|
|
||||||
Notification.Action deleteAction = task.createDeleteAction(mContext,
|
Notification.Action deleteAction = task.createDeleteAction(mContext,
|
||||||
mContext.getResources(),
|
mContext.getResources(),
|
||||||
|
|||||||
Reference in New Issue
Block a user