diff options
| author | 2024-04-04 14:07:23 -0400 | |
|---|---|---|
| committer | 2024-04-08 13:37:37 +0000 | |
| commit | 431c56498bf12d4d704c29f001e99d4d4f49dd77 (patch) | |
| tree | 05e263a9304905fc56d15f5368f12f7bd5b7a813 | |
| parent | f1e70448a03ae78cf3cbb22c1bd329714b720779 (diff) | |
Create ScreenshotResult class to simplify null checks
Bug: 329659738
Test: atest DefaultScreenshotActionsProviderTest
Flag: ACONFIG com.android.systemui.screenshot_shelf_ui DEVELOPMENT
Change-Id: I0fced77866375aa3d9fc447343884c96a9c6a936
Merged-In: I0fced77866375aa3d9fc447343884c96a9c6a936
6 files changed, 109 insertions, 122 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt index 60c44309fb07..6b0178336a72 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt @@ -23,21 +23,17 @@ import android.app.PendingIntent import android.app.assist.AssistContent import android.content.Context import android.content.Intent -import android.os.Process import android.os.UserHandle -import android.provider.DeviceConfig import android.util.Log import android.util.Pair import androidx.appcompat.content.res.AppCompatResources import com.android.app.tracing.coroutines.launch -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.res.R import com.android.systemui.screenshot.ActionIntentCreator.createEdit import com.android.systemui.screenshot.ActionIntentCreator.createShareWithSubject -import com.android.systemui.screenshot.ScreenshotController.SavedImageData import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED @@ -47,8 +43,6 @@ import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import java.text.DateFormat -import java.util.Date import kotlinx.coroutines.CoroutineScope /** @@ -56,7 +50,7 @@ import kotlinx.coroutines.CoroutineScope * implementation. */ interface ScreenshotActionsProvider { - fun setCompletedScreenshot(result: SavedImageData) + fun setCompletedScreenshot(result: ScreenshotSavedResult) fun isPendingSharedTransition(): Boolean fun onAssistContentAvailable(assistContent: AssistContent) {} @@ -85,8 +79,8 @@ constructor( @Assisted val windowTransition: () -> Pair<ActivityOptions, ExitTransitionCoordinator>, @Assisted val requestDismissal: () -> Unit, ) : ScreenshotActionsProvider { - private var pendingAction: ((SavedImageData) -> Unit)? = null - private var result: SavedImageData? = null + private var pendingAction: ((ScreenshotSavedResult) -> Unit)? = null + private var result: ScreenshotSavedResult? = null private var isPendingSharedTransition = false init { @@ -94,7 +88,7 @@ constructor( debugLog(LogConfig.DEBUG_ACTIONS) { "Preview tapped" } uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> - startSharedTransition(createEdit(result.uri, context), true) + startSharedTransition(createEdit(result.uri, context), result.user, true) } } viewModel.addAction( @@ -106,7 +100,7 @@ constructor( debugLog(LogConfig.DEBUG_ACTIONS) { "Edit tapped" } uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> - startSharedTransition(createEdit(result.uri, context), true) + startSharedTransition(createEdit(result.uri, context), result.user, true) } } ) @@ -119,74 +113,58 @@ constructor( debugLog(LogConfig.DEBUG_ACTIONS) { "Share tapped" } uiEventLogger.log(SCREENSHOT_SHARE_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> - startSharedTransition(createShareWithSubject(result.uri, result.subject), false) + startSharedTransition( + createShareWithSubject(result.uri, result.subject), + result.user, + false + ) } } ) - if (smartActionsEnabled(request.userHandle ?: Process.myUserHandle())) { - smartActionsProvider.requestQuickShare(request, requestId) { quickShare -> - if (!quickShare.actionIntent.isImmutable) { - viewModel.addAction( - ActionButtonViewModel( - quickShare.getIcon().loadDrawable(context), - quickShare.title, - quickShare.title, - ) { - debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" } - onDeferrableActionTapped { result -> - uiEventLogger.log( - SCREENSHOT_SMART_ACTION_TAPPED, - 0, - request.packageNameString - ) - sendPendingIntent( - smartActionsProvider - .wrapIntent( - quickShare, - result.uri, - result.subject, - requestId - ) - .actionIntent - ) - } + smartActionsProvider.requestQuickShare(request, requestId) { quickShare -> + if (!quickShare.actionIntent.isImmutable) { + viewModel.addAction( + ActionButtonViewModel( + quickShare.getIcon().loadDrawable(context), + quickShare.title, + quickShare.title + ) { + debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" } + onDeferrableActionTapped { result -> + uiEventLogger.log( + SCREENSHOT_SMART_ACTION_TAPPED, + 0, + request.packageNameString + ) + sendPendingIntent( + smartActionsProvider + .wrapIntent(quickShare, result.uri, result.subject, requestId) + .actionIntent + ) } - ) - } else { - Log.w(TAG, "Received immutable quick share pending intent; ignoring") - } + } + ) + } else { + Log.w(TAG, "Received immutable quick share pending intent; ignoring") } } } - override fun setCompletedScreenshot(result: SavedImageData) { + override fun setCompletedScreenshot(result: ScreenshotSavedResult) { if (this.result != null) { Log.e(TAG, "Got a second completed screenshot for existing request!") return } - if (result.uri == null || result.owner == null || result.imageTime == null) { - Log.e(TAG, "Invalid result provided!") - return - } - if (result.subject == null) { - result.subject = getSubjectString(result.imageTime) - } this.result = result pendingAction?.invoke(result) - if (smartActionsEnabled(result.owner)) { - smartActionsProvider.requestSmartActions(request, requestId, result) { smartActions -> - viewModel.addActions( - smartActions.map { - ActionButtonViewModel( - it.getIcon().loadDrawable(context), - it.title, - it.title, - ) { - sendPendingIntent(it.actionIntent) - } + smartActionsProvider.requestSmartActions(request, requestId, result) { smartActions -> + viewModel.addActions( + smartActions.map { + ActionButtonViewModel(it.getIcon().loadDrawable(context), it.title, it.title) { + sendPendingIntent(it.actionIntent) } - ) - } + } + ) } } @@ -194,17 +172,15 @@ constructor( return isPendingSharedTransition } - private fun onDeferrableActionTapped(onResult: (SavedImageData) -> Unit) { + private fun onDeferrableActionTapped(onResult: (ScreenshotSavedResult) -> Unit) { result?.let { onResult.invoke(it) } ?: run { pendingAction = onResult } } - private fun startSharedTransition(intent: Intent, overrideTransition: Boolean) { - val user = - result?.owner - ?: run { - Log.wtf(TAG, "User handle not provided in screenshot result! Result: $result") - return - } + private fun startSharedTransition( + intent: Intent, + user: UserHandle, + overrideTransition: Boolean + ) { isPendingSharedTransition = true applicationScope.launch("$TAG#launchIntentAsync") { actionExecutor.launchIntent(intent, windowTransition.invoke(), user, overrideTransition) @@ -225,21 +201,6 @@ constructor( } } - private fun smartActionsEnabled(user: UserHandle): Boolean { - val savingToOtherUser = user != Process.myUserHandle() - return !savingToOtherUser && - DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, - true - ) - } - - private fun getSubjectString(imageTime: Long): String { - val subjectDate = DateFormat.getDateTimeInstance().format(Date(imageTime)) - return String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate) - } - @AssistedFactory interface Factory : ScreenshotActionsProvider.Factory { override fun create( @@ -252,6 +213,5 @@ constructor( companion object { private const val TAG = "ScreenshotActionsProvider" - private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)" } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 1e513b200ac4..20098873c36c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -942,7 +942,7 @@ public class ScreenshotController { private void saveScreenshotInBackground( ScreenshotData screenshot, UUID requestId, Consumer<Uri> finisher) { ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor, - requestId, screenshot.getBitmap(), screenshot.getUserHandle(), mDisplayId); + requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(), mDisplayId); future.addListener(() -> { try { ImageExporter.Result result = future.get(); @@ -950,12 +950,8 @@ public class ScreenshotController { logScreenshotResultStatus(result.uri, screenshot.getUserHandle()); mScreenshotHandler.resetTimeout(); if (result.uri != null) { - final SavedImageData savedImageData = new SavedImageData(); - savedImageData.uri = result.uri; - savedImageData.owner = screenshot.getUserHandle(); - savedImageData.imageTime = result.timestamp; - mActionsProvider.setCompletedScreenshot(savedImageData); - mViewProxy.setChipIntents(savedImageData); + mActionsProvider.setCompletedScreenshot(new ScreenshotSavedResult( + result.uri, screenshot.getUserOrDefault(), result.timestamp)); } if (DEBUG_CALLBACK) { Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) " diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt index 92e933a9557b..4fdd90bdcded 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt @@ -5,6 +5,7 @@ import android.graphics.Bitmap import android.graphics.Insets import android.graphics.Rect import android.net.Uri +import android.os.Process import android.os.UserHandle import android.view.Display import android.view.WindowManager.ScreenshotSource @@ -31,6 +32,10 @@ data class ScreenshotData( val packageNameString: String get() = if (topComponent == null) "" else topComponent!!.packageName + fun getUserOrDefault(): UserHandle { + return userHandle ?: Process.myUserHandle() + } + companion object { @JvmStatic fun fromRequest(request: ScreenshotRequest, displayId: Int = Display.DEFAULT_DISPLAY) = diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSavedResult.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSavedResult.kt new file mode 100644 index 000000000000..5b6e7ac3e4e7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSavedResult.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 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.net.Uri +import android.os.UserHandle +import java.text.DateFormat +import java.util.Date + +/** + * Represents a saved screenshot, with the uri and user it was saved to as well as the time it was + * saved. + */ +data class ScreenshotSavedResult(val uri: Uri, val user: UserHandle, val imageTime: Long) { + val subject: String + + init { + val subjectDate = DateFormat.getDateTimeInstance().format(Date(imageTime)) + subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate) + } + + companion object { + private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt index 2eaff8654a9e..9a50bab469bb 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt @@ -65,10 +65,9 @@ constructor( onAction: (Notification.Action) -> Unit ) { val bitmap = data.bitmap ?: return - val user = data.userHandle ?: return val component = data.topComponent ?: ComponentName("", "") - requestQuickShareAction(id, bitmap, component, user) { quickShareAction -> - onAction(quickShareAction) + requestQuickShareAction(id, bitmap, component, data.getUserOrDefault()) { quickShare -> + onAction(quickShare) } } @@ -83,14 +82,19 @@ constructor( fun requestSmartActions( data: ScreenshotData, id: String, - result: ScreenshotController.SavedImageData, + result: ScreenshotSavedResult, onActions: (List<Notification.Action>) -> Unit ) { val bitmap = data.bitmap ?: return - val user = data.userHandle ?: return - val uri = result.uri ?: return val component = data.topComponent ?: ComponentName("", "") - requestSmartActions(id, bitmap, component, user, uri, REGULAR_SMART_ACTIONS) { actions -> + requestSmartActions( + id, + bitmap, + component, + data.getUserOrDefault(), + result.uri, + REGULAR_SMART_ACTIONS + ) { actions -> onActions(actions) } } @@ -197,7 +201,7 @@ constructor( onActions(listOf()) return } - var smartActionsFuture: CompletableFuture<List<Notification.Action>> + val smartActionsFuture: CompletableFuture<List<Notification.Action>> val startTimeMs = SystemClock.uptimeMillis() try { smartActionsFuture = @@ -266,6 +270,7 @@ constructor( Log.e(TAG, "Error in notifyScreenshotOp: ", e) } } + private fun isSmartActionsEnabled(user: UserHandle): Boolean { // Smart actions don't yet work for cross-user saves. val savingToOtherUser = user !== Process.myUserHandle() diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt index 4a5cf57e6fa8..7226b1de022d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt @@ -67,14 +67,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { private val requestDismissal = mock<() -> Unit>() private val request = ScreenshotData.forTesting() - private val invalidResult = ScreenshotController.SavedImageData() - private val validResult = - ScreenshotController.SavedImageData().apply { - uri = Uri.EMPTY - owner = UserHandle.OWNER - subject = "Test" - imageTime = 0 - } + private val validResult = ScreenshotSavedResult(Uri.EMPTY, android.os.Process.myUserHandle(), 0) private lateinit var viewModel: ScreenshotViewModel private lateinit var actionsProvider: ScreenshotActionsProvider @@ -109,17 +102,6 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { } @Test - fun actionAccessed_withInvalidResult_doesNothing() { - actionsProvider = createActionsProvider() - - actionsProvider.setCompletedScreenshot(invalidResult) - viewModel.previewAction.value!!.invoke() - viewModel.actions.value[1].onClicked!!.invoke() - - verifyNoMoreInteractions(actionIntentExecutor) - } - - @Test @Ignore("b/332526567") fun actionAccessed_withResult_launchesIntent() = runTest { actionsProvider = createActionsProvider() |