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

Commit e6ad101e authored by Matt Casey's avatar Matt Casey Committed by Automerger Merge Worker
Browse files

Merge "Fetch context URL from the top-most app, send with share if available."...

Merge "Fetch context URL from the top-most app, send with share if available." into tm-qpr-dev am: 633bd1e8

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21059523



Change-Id: Ifbec1437c40942f6209056d44ed01402c887e901
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 4180c689 633bd1e8
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -25,8 +25,22 @@ import android.net.Uri
import com.android.systemui.R

object ActionIntentCreator {
    /** @return a chooser intent to share the given URI. */
    fun createShareIntent(uri: Uri) = createShareIntent(uri, null, null)

    /** @return a chooser intent to share the given URI with the optional provided subject. */
    fun createShareIntent(uri: Uri, subject: String?): Intent {
    fun createShareIntentWithSubject(uri: Uri, subject: String?) =
        createShareIntent(uri, subject = subject)

    /** @return a chooser intent to share the given URI with the optional provided extra text. */
    fun createShareIntentWithExtraText(uri: Uri, extraText: String?) =
        createShareIntent(uri, extraText = extraText)

    private fun createShareIntent(
        uri: Uri,
        subject: String? = null,
        extraText: String? = null
    ): Intent {
        // Create a share intent, this will always go through the chooser activity first
        // which should not trigger auto-enter PiP
        val sharingIntent =
@@ -43,6 +57,7 @@ object ActionIntentCreator {
                    )

                putExtra(Intent.EXTRA_SUBJECT, subject)
                putExtra(Intent.EXTRA_TEXT, extraText)
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            }
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.IAssistDataReceiver;
import android.app.assist.AssistContent;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;

import javax.inject.Inject;

/**
 * Can be used to request the AssistContent from a provided task id, useful for getting the web uri
 * if provided from the task.
 *
 * Forked from
 * packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
 */
@SysUISingleton
public class AssistContentRequester {
    private static final String TAG = "AssistContentRequester";
    private static final String ASSIST_KEY_CONTENT = "content";

    /** For receiving content, called on the main thread. */
    public interface Callback {
        /**
         * Called when the {@link android.app.assist.AssistContent} of the requested task is
         * available.
         **/
        void onAssistContentAvailable(AssistContent assistContent);
    }

    private final IActivityTaskManager mActivityTaskManager;
    private final String mPackageName;
    private final Executor mCallbackExecutor;
    private final Executor mSystemInteractionExecutor;

    // If system loses the callback, our internal cache of original callback will also get cleared.
    private final Map<Object, Callback> mPendingCallbacks =
            Collections.synchronizedMap(new WeakHashMap<>());

    @Inject
    public AssistContentRequester(Context context, @Main Executor mainExecutor,
            @Background Executor bgExecutor) {
        mActivityTaskManager = ActivityTaskManager.getService();
        mPackageName = context.getApplicationContext().getPackageName();
        mCallbackExecutor = mainExecutor;
        mSystemInteractionExecutor = bgExecutor;
    }

    /**
     * Request the {@link AssistContent} from the task with the provided id.
     *
     * @param taskId to query for the content.
     * @param callback to call when the content is available, called on the main thread.
     */
    public void requestAssistContent(final int taskId, final Callback callback) {
        // ActivityTaskManager interaction here is synchronous, so call off the main thread.
        mSystemInteractionExecutor.execute(() -> {
            try {
                mActivityTaskManager.requestAssistDataForTask(
                        new AssistDataReceiver(callback, this), taskId, mPackageName);
            } catch (RemoteException e) {
                Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
            }
        });
    }

    private void executeOnMainExecutor(Runnable callback) {
        mCallbackExecutor.execute(callback);
    }

    private static final class AssistDataReceiver extends IAssistDataReceiver.Stub {

        // The AssistDataReceiver binder callback object is passed to a system server, that may
        // keep hold of it for longer than the lifetime of the AssistContentRequester object,
        // potentially causing a memory leak. In the callback passed to the system server, only
        // keep a weak reference to the parent object and lookup its callback if it still exists.
        private final WeakReference<AssistContentRequester> mParentRef;
        private final Object mCallbackKey = new Object();

        AssistDataReceiver(Callback callback, AssistContentRequester parent) {
            parent.mPendingCallbacks.put(mCallbackKey, callback);
            mParentRef = new WeakReference<>(parent);
        }

        @Override
        public void onHandleAssistData(Bundle data) {
            if (data == null) {
                return;
            }

            final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
            if (content == null) {
                Log.e(TAG, "Received AssistData, but no AssistContent found");
                return;
            }

            AssistContentRequester requester = mParentRef.get();
            if (requester != null) {
                Callback callback = requester.mPendingCallbacks.get(mCallbackKey);
                if (callback != null) {
                    requester.executeOnMainExecutor(
                            () -> callback.onAssistContentAvailable(content));
                } else {
                    Log.d(TAG, "Callback received after calling UI was disposed of");
                }
            } else {
                Log.d(TAG, "Callback received after Requester was collected");
            }
        }

        @Override
        public void onHandleAssistScreenshot(Bitmap screenshot) {}
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -366,7 +366,7 @@ public class LongScreenshotActivity extends Activity {

    private void doShare(Uri uri) {
        if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
            Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri, null);
            Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
            mActionExecutor.launchIntentAsync(shareIntent, null,
                    mScreenshotUserHandle.getIdentifier(), false);
        } else {
+17 −2
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.app.ExitTransitionCoordinator;
import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks;
import android.app.ICompatCameraControlCallback;
import android.app.Notification;
import android.app.assist.AssistContent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -281,6 +282,7 @@ public class ScreenshotController {
    private final ActionIntentExecutor mActionExecutor;
    private final UserManager mUserManager;
    private final WorkProfileMessageController mWorkProfileMessageController;
    private final AssistContentRequester mAssistContentRequester;

    private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
        if (DEBUG_INPUT) {
@@ -328,7 +330,8 @@ public class ScreenshotController {
            ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
            ActionIntentExecutor actionExecutor,
            UserManager userManager,
            WorkProfileMessageController workProfileMessageController
            WorkProfileMessageController workProfileMessageController,
            AssistContentRequester assistContentRequester
    ) {
        mScreenshotSmartActions = screenshotSmartActions;
        mNotificationsController = screenshotNotificationsController;
@@ -361,6 +364,7 @@ public class ScreenshotController {
        mActionExecutor = actionExecutor;
        mUserManager = userManager;
        mWorkProfileMessageController = workProfileMessageController;
        mAssistContentRequester = assistContentRequester;

        mAccessibilityManager = AccessibilityManager.getInstance(mContext);

@@ -466,7 +470,18 @@ public class ScreenshotController {
                    mContext.getDrawable(R.drawable.overlay_badge_background),
                    screenshot.getUserHandle()));
        }
        mScreenshotView.setScreenshot(mScreenBitmap, screenshot.getInsets());
        mScreenshotView.setScreenshot(screenshot);

        if (screenshot.getTaskId() >= 0) {
            mAssistContentRequester.requestAssistContent(screenshot.getTaskId(),
                    new AssistContentRequester.Callback() {
                        @Override
                        public void onAssistContentAvailable(AssistContent assistContent) {
                            screenshot.setContextUrl(assistContent.getWebUri());
                        }
                    });
        }

        if (DEBUG_WINDOW) {
            Log.d(TAG, "setContentView: " + mScreenshotView);
        }
+3 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.content.ComponentName
import android.graphics.Bitmap
import android.graphics.Insets
import android.graphics.Rect
import android.net.Uri
import android.os.UserHandle
import android.view.WindowManager.ScreenshotSource
import android.view.WindowManager.ScreenshotType
@@ -21,6 +22,8 @@ data class ScreenshotData(
    var taskId: Int,
    var insets: Insets,
    var bitmap: Bitmap?,
    /** App-provided URL representing the content the user was looking at in the screenshot. */
    var contextUrl: Uri? = null,
) {
    val packageNameString: String
        get() = if (topComponent == null) "" else topComponent!!.packageName
Loading