Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 372c79af authored by Miranda Kephart's avatar Miranda Kephart Committed by Android (Google) Code Review
Browse files

Merge "Create ScreenshotResult class to simplify null checks" into main

parents c28bd6bb 2b79468a
Loading
Loading
Loading
Loading
+48 −88
Original line number Diff line number Diff line
@@ -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,18 +113,21 @@ 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,
                        quickShare.title
                    ) {
                        debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" }
                        onDeferrableActionTapped { result ->
@@ -141,12 +138,7 @@ constructor(
                            )
                            sendPendingIntent(
                                smartActionsProvider
                                        .wrapIntent(
                                            quickShare,
                                            result.uri,
                                            result.subject,
                                            requestId
                                        )
                                    .wrapIntent(quickShare, result.uri, result.subject, requestId)
                                    .actionIntent
                            )
                        }
@@ -157,54 +149,38 @@ constructor(
            }
        }
    }
    }

    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,
                        ) {
                    ActionButtonViewModel(it.getIcon().loadDrawable(context), it.title, it.title) {
                        sendPendingIntent(it.actionIntent)
                    }
                }
            )
        }
    }
    }

    override fun isPendingSharedTransition(): Boolean {
        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)"
    }
}
+3 −7
Original line number Diff line number Diff line
@@ -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>) "
+5 −0
Original line number Diff line number Diff line
@@ -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) =
+39 −0
Original line number Diff line number Diff line
/*
 * 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)"
    }
}
+13 −8
Original line number Diff line number Diff line
@@ -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()
Loading