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

Commit 5bfa0206 authored by Evan Severson's avatar Evan Severson
Browse files

Notify ClipboardService when a trusted paste action is performed

This is to suppress the clip access toast (called notification in code)
when a trusted component can assert that the user intended to provide
clip access to a given application.

Test: Manual
Bug: 363318732
Fixes: 404562929
Flag: android.permission.flags.system_selection_toolbar_enabled

Change-Id: I5d60b7b0fe3728cc5414032b4f53a16f1d26c57e
parent dc595f57
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -71,9 +71,9 @@ public final class DefaultSelectionToolbarRenderService extends SelectionToolbar
                : showInfo.widgetToken;

        if (mToolbarCache.indexOfKey(callingUid) < 0) {
            RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(this,
            RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(callingUid, this,
                    widgetToken, showInfo,
                    callbackWrapper, this::transferTouch);
                    callbackWrapper, this::transferTouch, this::onPasteAction);
            mToolbarCache.put(callingUid, new Pair<>(widgetToken, toolbar));
        }
        Slog.v(TAG, "onShow() for " + widgetToken);
+4 −2
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.os.IBinder;
 *
 * @hide
 */
oneway interface ISelectionToolbarRenderServiceCallback {
    void transferTouch(in IBinder source, in IBinder target);
interface ISelectionToolbarRenderServiceCallback {
    oneway void transferTouch(in IBinder source, in IBinder target);

    void onPasteAction(int uid);
}
+16 −6
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ final class RemoteSelectionToolbar {
    private static final int MIN_OVERFLOW_SIZE = 2;
    private static final int MAX_OVERFLOW_SIZE = 4;

    private int mCallingUid;

    private final Context mContext;

    /* Margins between the popup window and its content. */
@@ -121,6 +123,8 @@ final class RemoteSelectionToolbar {
    private IBinder mHostInputToken;
    private final SelectionToolbarRenderService.RemoteCallbackWrapper mCallbackWrapper;
    private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
    private final SelectionToolbarRenderService.OnPasteActionCallback mOnPasteActionCallback;

    private int mPopupWidth;
    private int mPopupHeight;
    // Coordinates to show the toolbar relative to the specified view port
@@ -163,13 +167,16 @@ final class RemoteSelectionToolbar {
    private final Rect mTempContentRectForRoot = new Rect();
    private final int[] mTempCoords = new int[2];

    RemoteSelectionToolbar(Context context, long selectionToolbarToken, ShowInfo showInfo,
            SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper,
            SelectionToolbarRenderService.TransferTouchListener transferTouchListener) {
    RemoteSelectionToolbar(int callingUid, Context context, long selectionToolbarToken,
            ShowInfo showInfo, SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper,
            SelectionToolbarRenderService.TransferTouchListener transferTouchListener,
            SelectionToolbarRenderService.OnPasteActionCallback onPasteActionCallback) {
        mCallingUid = callingUid;
        mContext = wrapContext(context, showInfo);
        mSelectionToolbarToken = selectionToolbarToken;
        mCallbackWrapper = callbackWrapper;
        mTransferTouchListener = transferTouchListener;
        mOnPasteActionCallback = onPasteActionCallback;
        mHostInputToken = showInfo.hostInputToken;
        mContentContainer = createContentContainer(mContext);
        mMarginHorizontal = mContext.getResources()
@@ -244,10 +251,13 @@ final class RemoteSelectionToolbar {
                null); // TODO(b/215497659): should handle hide after animation
        mMenuItemButtonOnClickListener = v -> {
            Object tag = v.getTag();
            if (!(tag instanceof ToolbarMenuItem)) {
                return;
            if (tag instanceof ToolbarMenuItem toolbarMenuItem) {
                if (toolbarMenuItem.itemId == R.id.paste
                        || toolbarMenuItem.itemId == R.id.pasteAsPlainText) {
                    mOnPasteActionCallback.onPasteAction(mCallingUid);
                }
                mCallbackWrapper.onMenuItemClicked(toolbarMenuItem.itemIndex);
            }
            mCallbackWrapper.onMenuItemClicked(((ToolbarMenuItem) tag).itemIndex);
        };
    }

+23 −0
Original line number Diff line number Diff line
@@ -171,6 +171,19 @@ public abstract class SelectionToolbarRenderService extends Service {
        }
    }

    protected void onPasteAction(int uid) {
        final ISelectionToolbarRenderServiceCallback callback = mServiceCallback;
        if (callback == null) {
            Log.e(TAG, "onPasteAction(): no server callback");
            return;
        }
        try {
            callback.onPasteAction(uid);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to notify onPasteAction", e);
        }
    }

    /**
     * Called when showing the selection toolbar.
     */
@@ -295,4 +308,14 @@ public abstract class SelectionToolbarRenderService extends Service {
         */
        void onTransferTouch(IBinder source, IBinder target);
    }

    /**
     * A listener to notify the service to the paste action.
     */
    public interface OnPasteActionCallback {
        /**
         * Notify the service to the paste action.
         */
        void onPasteAction(int callingUid);
    }
}
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.server.clipboard;

/**
 * Internal interface for the clipboard manager.
 */
public interface ClipboardManagerInternal {

    /**
     * Notify that there was a recent action taken by the user that the system trusts was an
     * intentional authorization of clip data.
     *
     * @param uid The uid expected to access clip data.
     */
    void notifyUserAuthorizedClipAccess(int uid);
}
Loading