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

Commit b04e668e authored by Matt Casey's avatar Matt Casey Committed by Android (Google) Code Review
Browse files

Merge "Add screenshot support for preferred screenshot editor." into main

parents 2ae29b62 b13d7690
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
    private val actionExecutor = mock<ActionExecutor>()
    private val uiEventLogger = mock<UiEventLogger>()
    private val actionsCallback = mock<ScreenshotActionsController.ActionsCallback>()
    private val actionIntentCreator = ActionIntentCreator(context, context.packageManager)

    private val request = ScreenshotData.forTesting(userHandle = UserHandle.OWNER)
    private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0)
@@ -196,6 +197,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
        return DefaultScreenshotActionsProvider(
            context,
            uiEventLogger,
            actionIntentCreator,
            UUID.randomUUID(),
            request,
            actionExecutor,
+10 −1
Original line number Diff line number Diff line
@@ -501,7 +501,16 @@
    <!-- Smartspace trampoline activity that is used when the user taps smartspace. -->
    <string name="config_smartspaceTrampolineActivityComponent" translatable="false">com.google.android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity</string>

    <!-- Screenshot editing default activity.  Must handle ACTION_EDIT image/png intents.
    <!-- Screenshot editing default activity. Will only be used if the provided component exists and
      is enabled.

      Must handle ACTION_EDIT image/png intents.
      Blank falls back to config_screenshotEditor.
      This name is in the ComponentName flattened format (package/class)  -->
    <string name="config_preferredScreenshotEditor" translatable="false"></string>

    <!-- Screenshot editing activity used if config_preferredScreenshotEditor is not available.
     Must handle ACTION_EDIT image/png intents.
         Blank sends the user to the Chooser first.
         This name is in the ComponentName flattened format (package/class)  -->
    <string name="config_screenshotEditor" translatable="false"></string>
+50 −11
Original line number Diff line number Diff line
@@ -22,12 +22,19 @@ import android.content.ComponentName
import android.content.ContentProvider
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import com.android.systemui.screenshot.scroll.LongScreenshotActivity
import com.android.systemui.shared.Flags.usePreferredImageEditor
import javax.inject.Inject

object ActionIntentCreator {
@SysUISingleton
class ActionIntentCreator
@Inject
constructor(private val context: Context, private val packageManager: PackageManager) {
    /** @return a chooser intent to share the given URI. */
    fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null)

@@ -54,7 +61,7 @@ object ActionIntentCreator {
                clipData =
                    ClipData(
                        ClipDescription("content", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)),
                        ClipData.Item(uri)
                        ClipData.Item(uri),
                    )

                subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) }
@@ -70,17 +77,22 @@ object ActionIntentCreator {
    }

    /**
     * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if
     *   available.
     * @return an ACTION_EDIT intent for the given URI, directed to config_preferredScreenshotEditor
     *   if enabled, falling back to config_screenshotEditor if that's non-empty.
     */
    fun createEdit(rawUri: Uri, context: Context): Intent {
    fun createEdit(rawUri: Uri): Intent {
        val uri = uriWithoutUserId(rawUri)
        val editIntent = Intent(Intent.ACTION_EDIT)

        if (usePreferredImageEditor()) {
            // Use the preferred editor if it's available, otherwise fall back to the default editor
            editIntent.component = preferredEditor() ?: defaultEditor()
        } else {
            val editor = context.getString(R.string.config_screenshotEditor)
            if (editor.isNotEmpty()) {
                editIntent.component = ComponentName.unflattenFromString(editor)
            }
        }

        return editIntent
            .setDataAndType(uri, "image/png")
@@ -92,7 +104,7 @@ object ActionIntentCreator {
    }

    /** @return an Intent to start the LongScreenshotActivity */
    fun createLongScreenshotIntent(owner: UserHandle, context: Context): Intent {
    fun createLongScreenshotIntent(owner: UserHandle): Intent {
        return Intent(context, LongScreenshotActivity::class.java)
            .putExtra(LongScreenshotActivity.EXTRA_SCREENSHOT_USER_HANDLE, owner)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -100,9 +112,36 @@ object ActionIntentCreator {
            .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
    }

    private fun preferredEditor(): ComponentName? =
        runCatching {
                val preferredEditor = context.getString(R.string.config_preferredScreenshotEditor)
                val component = ComponentName.unflattenFromString(preferredEditor) ?: return null

                val info =
                    packageManager.getPackageInfo(
                        component.packageName,
                        PackageManager.GET_ACTIVITIES,
                    )

                return info.activities
                    ?.firstOrNull { it.componentName.className.equals(component.className) }
                    ?.componentName
            }
            .getOrNull()

    private fun defaultEditor(): ComponentName? =
        runCatching {
                context.getString(R.string.config_screenshotEditor).let {
                    ComponentName.unflattenFromString(it)
                }
            }
            .getOrNull()

    companion object {
        private const val EXTRA_EDIT_SOURCE = "edit_source"
        private const val EDIT_SOURCE_SCREENSHOT = "screenshot"
    }
}

/**
 * URIs here are passed only via Intent which are sent to the target user via Intent. Because of
+4 −2
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler
    private RequestCallback mCurrentRequestCallback;
    private String mPackageName = "";
    private final BroadcastReceiver mCopyBroadcastReceiver;
    private final ActionIntentCreator mActionIntentCreator;

    /** Tracks config changes that require re-creating UI */
    private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
@@ -174,6 +175,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler
            MessageContainerController messageContainerController,
            Provider<ScreenshotSoundController> screenshotSoundController,
            AnnouncementResolver announcementResolver,
            ActionIntentCreator actionIntentCreator,
            @Assisted Display display
    ) {
        mScreenshotSmartActions = screenshotSmartActions;
@@ -201,6 +203,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler
        mMessageContainerController = messageContainerController;
        mAssistContentRequester = assistContentRequester;
        mAnnouncementResolver = announcementResolver;
        mActionIntentCreator = actionIntentCreator;

        mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId());

@@ -509,8 +512,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler
    private void executeBatchScrollCapture(ScrollCaptureResponse response, UserHandle owner) {
        mScrollCaptureExecutor.executeBatchScrollCapture(response,
                () -> {
                    final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent(
                            owner, mContext);
                    final Intent intent = mActionIntentCreator.createLongScreenshotIntent(owner);
                    mContext.startActivity(intent);
                },
                mViewProxy::restoreNonScrollingUi,
+8 −7
Original line number Diff line number Diff line
@@ -24,9 +24,6 @@ import androidx.appcompat.content.res.AppCompatResources
import com.android.internal.logging.UiEventLogger
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.ActionIntentCreator.createShareWithText
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
@@ -70,6 +67,7 @@ class DefaultScreenshotActionsProvider
constructor(
    private val context: Context,
    private val uiEventLogger: UiEventLogger,
    private val actionIntentCreator: ActionIntentCreator,
    @Assisted val requestId: UUID,
    @Assisted val request: ScreenshotData,
    @Assisted val actionExecutor: ActionExecutor,
@@ -88,7 +86,7 @@ constructor(
                uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString)
                onDeferrableActionTapped { result ->
                    actionExecutor.startSharedTransition(
                        createEdit(result.uri, context),
                        actionIntentCreator.createEdit(result.uri),
                        result.user,
                        true,
                    )
@@ -110,9 +108,12 @@ constructor(
                val uri = webUri
                val shareIntent =
                    if (screenshotContextUrl() && uri != null) {
                        createShareWithText(result.uri, extraText = uri.toString())
                        actionIntentCreator.createShareWithText(
                            result.uri,
                            extraText = uri.toString(),
                        )
                    } else {
                        createShareWithSubject(result.uri, result.subject)
                        actionIntentCreator.createShareWithSubject(result.uri, result.subject)
                    }
                actionExecutor.startSharedTransition(shareIntent, result.user, false)
            }
@@ -130,7 +131,7 @@ constructor(
            uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString)
            onDeferrableActionTapped { result ->
                actionExecutor.startSharedTransition(
                    createEdit(result.uri, context),
                    actionIntentCreator.createEdit(result.uri),
                    result.user,
                    true,
                )
Loading