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

Commit 15739d30 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Add explicit method to clear clipboard."

parents 03b91d77 d60e07f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -8972,6 +8972,7 @@ package android.content {
  public class ClipboardManager extends android.text.ClipboardManager {
  public class ClipboardManager extends android.text.ClipboardManager {
    method public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener);
    method public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener);
    method public void clearPrimaryClip();
    method public android.content.ClipData getPrimaryClip();
    method public android.content.ClipData getPrimaryClip();
    method public android.content.ClipDescription getPrimaryClipDescription();
    method public android.content.ClipDescription getPrimaryClipDescription();
    method public deprecated java.lang.CharSequence getText();
    method public deprecated java.lang.CharSequence getText();
+34 −20
Original line number Original line Diff line number Diff line
@@ -16,13 +16,16 @@


package android.content;
package android.content;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.annotation.SystemService;
import android.os.Handler;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.ServiceManager.ServiceNotFoundException;


import com.android.internal.util.Preconditions;

import java.util.ArrayList;
import java.util.ArrayList;


/**
/**
@@ -45,6 +48,7 @@ import java.util.ArrayList;
@SystemService(Context.CLIPBOARD_SERVICE)
@SystemService(Context.CLIPBOARD_SERVICE)
public class ClipboardManager extends android.text.ClipboardManager {
public class ClipboardManager extends android.text.ClipboardManager {
    private final Context mContext;
    private final Context mContext;
    private final Handler mHandler;
    private final IClipboard mService;
    private final IClipboard mService;


    private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners
    private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners
@@ -52,20 +56,11 @@ public class ClipboardManager extends android.text.ClipboardManager {


    private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener
    private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener
            = new IOnPrimaryClipChangedListener.Stub() {
            = new IOnPrimaryClipChangedListener.Stub() {
        public void dispatchPrimaryClipChanged() {
            mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED);
        }
    };

    static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1;

    private final Handler mHandler = new Handler() {
        @Override
        @Override
        public void handleMessage(Message msg) {
        public void dispatchPrimaryClipChanged() {
            switch (msg.what) {
            mHandler.post(() -> {
                case MSG_REPORT_PRIMARY_CLIP_CHANGED:
                reportPrimaryClipChanged();
                reportPrimaryClipChanged();
            }
            });
        }
        }
    };
    };


@@ -89,6 +84,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
    /** {@hide} */
    /** {@hide} */
    public ClipboardManager(Context context, Handler handler) throws ServiceNotFoundException {
    public ClipboardManager(Context context, Handler handler) throws ServiceNotFoundException {
        mContext = context;
        mContext = context;
        mHandler = handler;
        mService = IClipboard.Stub.asInterface(
        mService = IClipboard.Stub.asInterface(
                ServiceManager.getServiceOrThrow(Context.CLIPBOARD_SERVICE));
                ServiceManager.getServiceOrThrow(Context.CLIPBOARD_SERVICE));
    }
    }
@@ -98,22 +94,38 @@ public class ClipboardManager extends android.text.ClipboardManager {
     * is involved in normal cut and paste operations.
     * is involved in normal cut and paste operations.
     *
     *
     * @param clip The clipped data item to set.
     * @param clip The clipped data item to set.
     * @see #getPrimaryClip()
     * @see #clearPrimaryClip()
     */
     */
    public void setPrimaryClip(ClipData clip) {
    public void setPrimaryClip(@NonNull ClipData clip) {
        try {
        try {
            if (clip != null) {
            Preconditions.checkNotNull(clip);
            clip.prepareToLeaveProcess(true);
            clip.prepareToLeaveProcess(true);
            }
            mService.setPrimaryClip(clip, mContext.getOpPackageName());
            mService.setPrimaryClip(clip, mContext.getOpPackageName());
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
    }
    }


    /**
     * Clears any current primary clip on the clipboard.
     *
     * @see #setPrimaryClip(ClipData)
     */
    public void clearPrimaryClip() {
        try {
            mService.clearPrimaryClip(mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
    /**
     * Returns the current primary clip on the clipboard.
     * Returns the current primary clip on the clipboard.
     *
     * @see #setPrimaryClip(ClipData)
     */
     */
    public ClipData getPrimaryClip() {
    public @Nullable ClipData getPrimaryClip() {
        try {
        try {
            return mService.getPrimaryClip(mContext.getOpPackageName());
            return mService.getPrimaryClip(mContext.getOpPackageName());
        } catch (RemoteException e) {
        } catch (RemoteException e) {
@@ -124,8 +136,10 @@ public class ClipboardManager extends android.text.ClipboardManager {
    /**
    /**
     * Returns a description of the current primary clip on the clipboard
     * Returns a description of the current primary clip on the clipboard
     * but not a copy of its data.
     * but not a copy of its data.
     *
     * @see #setPrimaryClip(ClipData)
     */
     */
    public ClipDescription getPrimaryClipDescription() {
    public @Nullable ClipDescription getPrimaryClipDescription() {
        try {
        try {
            return mService.getPrimaryClipDescription(mContext.getOpPackageName());
            return mService.getPrimaryClipDescription(mContext.getOpPackageName());
        } catch (RemoteException e) {
        } catch (RemoteException e) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.IOnPrimaryClipChangedListener;
 */
 */
interface IClipboard {
interface IClipboard {
    void setPrimaryClip(in ClipData clip, String callingPackage);
    void setPrimaryClip(in ClipData clip, String callingPackage);
    void clearPrimaryClip(String callingPackage);
    ClipData getPrimaryClip(String pkg);
    ClipData getPrimaryClip(String pkg);
    ClipDescription getPrimaryClipDescription(String callingPackage);
    ClipDescription getPrimaryClipDescription(String callingPackage);
    boolean hasPrimaryClip(String callingPackage);
    boolean hasPrimaryClip(String callingPackage);
+19 −0
Original line number Original line Diff line number Diff line
@@ -9410,6 +9410,25 @@ public class ActivityManagerService extends IActivityManager.Stub
                    allowed = false;
                    allowed = false;
                }
                }
            }
            }
            if (pi.pathPermissions != null) {
                final int N = pi.pathPermissions.length;
                for (int i=0; i<N; i++) {
                    if (pi.pathPermissions[i] != null
                            && pi.pathPermissions[i].match(grantUri.uri.getPath())) {
                        if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
                            if (pi.pathPermissions[i].getReadPermission() != null) {
                                allowed = false;
                            }
                        }
                        if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
                            if (pi.pathPermissions[i].getWritePermission() != null) {
                                allowed = false;
                            }
                        }
                        break;
                    }
                }
            }
            if (allowed) {
            if (allowed) {
                return -1;
                return -1;
            }
            }
+93 −59
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.server.clipboard;
package com.android.server.clipboard;


import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
@@ -24,9 +25,9 @@ import android.app.KeyguardManager;
import android.content.ClipData;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipDescription;
import android.content.ContentProvider;
import android.content.ContentProvider;
import android.content.Context;
import android.content.IClipboard;
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
import android.content.IOnPrimaryClipChangedListener;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
@@ -37,7 +38,6 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
import android.os.IUserManager;
import android.os.IUserManager;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
@@ -49,14 +49,10 @@ import android.util.SparseArray;


import com.android.server.SystemService;
import com.android.server.SystemService;


import java.util.HashSet;
import java.util.List;

import java.lang.Thread;
import java.lang.Runnable;
import java.lang.InterruptedException;
import java.io.IOException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.RandomAccessFile;
import java.util.HashSet;
import java.util.List;


// The following class is Android Emulator specific. It is used to read and
// The following class is Android Emulator specific. It is used to read and
// write contents of the host system's clipboard.
// write contents of the host system's clipboard.
@@ -182,7 +178,8 @@ public class ClipboardService extends SystemService {
                                         new String[]{"text/plain"},
                                         new String[]{"text/plain"},
                                         new ClipData.Item(contents));
                                         new ClipData.Item(contents));
                        synchronized(mClipboards) {
                        synchronized(mClipboards) {
                            setPrimaryClipInternal(getClipboard(0), clip);
                            setPrimaryClipInternal(getClipboard(0), clip,
                                    android.os.Process.SYSTEM_UID);
                        }
                        }
                    }
                    }
                });
                });
@@ -218,7 +215,10 @@ public class ClipboardService extends SystemService {
        final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
        final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
                = new RemoteCallbackList<IOnPrimaryClipChangedListener>();
                = new RemoteCallbackList<IOnPrimaryClipChangedListener>();


        /** Current primary clip. */
        ClipData primaryClip;
        ClipData primaryClip;
        /** UID that set {@link #primaryClip}. */
        int primaryClipUid = android.os.Process.NOBODY_UID;


        final HashSet<String> activePermissionOwners
        final HashSet<String> activePermissionOwners
                = new HashSet<String>();
                = new HashSet<String>();
@@ -246,58 +246,28 @@ public class ClipboardService extends SystemService {
        @Override
        @Override
        public void setPrimaryClip(ClipData clip, String callingPackage) {
        public void setPrimaryClip(ClipData clip, String callingPackage) {
            synchronized (this) {
            synchronized (this) {
                if (clip != null && clip.getItemCount() <= 0) {
                if (clip == null || clip.getItemCount() <= 0) {
                    throw new IllegalArgumentException("No items");
                    throw new IllegalArgumentException("No items");
                }
                }
                if (clip.getItemAt(0).getText() != null &&
                    mHostClipboardMonitor != null) {
                    mHostClipboardMonitor.setHostClipboard(
                        clip.getItemAt(0).getText().toString());
                }
                final int callingUid = Binder.getCallingUid();
                final int callingUid = Binder.getCallingUid();
                if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
                if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
                            callingUid)) {
                            callingUid)) {
                    return;
                    return;
                }
                }
                checkDataOwnerLocked(clip, callingUid);
                checkDataOwnerLocked(clip, callingUid);
                final int userId = UserHandle.getUserId(callingUid);
                setPrimaryClipInternal(clip, callingUid);
                PerUserClipboard clipboard = getClipboard(userId);
                revokeUris(clipboard);
                setPrimaryClipInternal(clipboard, clip);
                List<UserInfo> related = getRelatedProfiles(userId);
                if (related != null) {
                    int size = related.size();
                    if (size > 1) { // Related profiles list include the current profile.
                        boolean canCopy = false;
                        try {
                            canCopy = !mUm.getUserRestrictions(userId).getBoolean(
                                    UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Remote Exception calling UserManager: " + e);
                        }
                        // Copy clip data to related users if allowed. If disallowed, then remove
                        // primary clip in related users to prevent pasting stale content.
                        if (!canCopy) {
                            clip = null;
                        } else {
                            // We want to fix the uris of the related user's clip without changing the
                            // uris of the current user's clip.
                            // So, copy the ClipData, and then copy all the items, so that nothing
                            // is shared in memmory.
                            clip = new ClipData(clip);
                            for (int i = clip.getItemCount() - 1; i >= 0; i--) {
                                clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
                            }
                            clip.fixUrisLight(userId);
                        }
                        for (int i = 0; i < size; i++) {
                            int id = related.get(i).id;
                            if (id != userId) {
                                setPrimaryClipInternal(getClipboard(id), clip);
                            }
            }
            }
        }
        }

        @Override
        public void clearPrimaryClip(String callingPackage) {
            synchronized (this) {
                final int callingUid = Binder.getCallingUid();
                if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
                        callingUid)) {
                    return;
                }
                }
                setPrimaryClipInternal(null, callingUid);
            }
            }
        }
        }


@@ -398,12 +368,74 @@ public class ClipboardService extends SystemService {
        return related;
        return related;
    }
    }


    void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) {
    void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
        // Push clipboard to host, if any
        if (mHostClipboardMonitor != null) {
            if (clip == null) {
                // Someone really wants the clipboard cleared, so push empty
                mHostClipboardMonitor.setHostClipboard("");
            } else if (clip.getItemCount() > 0) {
                final CharSequence text = clip.getItemAt(0).getText();
                if (text != null) {
                    mHostClipboardMonitor.setHostClipboard(text.toString());
                }
            }
        }

        // Update this user
        final int userId = UserHandle.getUserId(callingUid);
        setPrimaryClipInternal(getClipboard(userId), clip, callingUid);

        // Update related users
        List<UserInfo> related = getRelatedProfiles(userId);
        if (related != null) {
            int size = related.size();
            if (size > 1) { // Related profiles list include the current profile.
                boolean canCopy = false;
                try {
                    canCopy = !mUm.getUserRestrictions(userId).getBoolean(
                            UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Remote Exception calling UserManager: " + e);
                }
                // Copy clip data to related users if allowed. If disallowed, then remove
                // primary clip in related users to prevent pasting stale content.
                if (!canCopy) {
                    clip = null;
                } else {
                    // We want to fix the uris of the related user's clip without changing the
                    // uris of the current user's clip.
                    // So, copy the ClipData, and then copy all the items, so that nothing
                    // is shared in memmory.
                    clip = new ClipData(clip);
                    for (int i = clip.getItemCount() - 1; i >= 0; i--) {
                        clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
                    }
                    clip.fixUrisLight(userId);
                }
                for (int i = 0; i < size; i++) {
                    int id = related.get(i).id;
                    if (id != userId) {
                        setPrimaryClipInternal(getClipboard(id), clip, callingUid);
                    }
                }
            }
        }
    }

    void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
            int callingUid) {
        revokeUris(clipboard);
        clipboard.activePermissionOwners.clear();
        clipboard.activePermissionOwners.clear();
        if (clip == null && clipboard.primaryClip == null) {
        if (clip == null && clipboard.primaryClip == null) {
            return;
            return;
        }
        }
        clipboard.primaryClip = clip;
        clipboard.primaryClip = clip;
        if (clip != null) {
            clipboard.primaryClipUid = callingUid;
        } else {
            clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
        }
        if (clip != null) {
        if (clip != null) {
            final ClipDescription description = clip.getDescription();
            final ClipDescription description = clip.getDescription();
            if (description != null) {
            if (description != null) {
@@ -479,12 +511,12 @@ public class ClipboardService extends SystemService {
        }
        }
    }
    }


    private final void grantUriLocked(Uri uri, String pkg, int userId) {
    private final void grantUriLocked(Uri uri, int primaryClipUid, String pkg, int userId) {
        long ident = Binder.clearCallingIdentity();
        long ident = Binder.clearCallingIdentity();
        try {
        try {
            int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
            int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
            uri = ContentProvider.getUriWithoutUserId(uri);
            uri = ContentProvider.getUriWithoutUserId(uri);
            mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
            mAm.grantUriPermissionFromOwner(mPermissionOwner, primaryClipUid, pkg,
                    uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
                    uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
        } finally {
        } finally {
@@ -492,13 +524,14 @@ public class ClipboardService extends SystemService {
        }
        }
    }
    }


    private final void grantItemLocked(ClipData.Item item, String pkg, int userId) {
    private final void grantItemLocked(ClipData.Item item, int primaryClipUid, String pkg,
            int userId) {
        if (item.getUri() != null) {
        if (item.getUri() != null) {
            grantUriLocked(item.getUri(), pkg, userId);
            grantUriLocked(item.getUri(), primaryClipUid, pkg, userId);
        }
        }
        Intent intent = item.getIntent();
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
        if (intent != null && intent.getData() != null) {
            grantUriLocked(intent.getData(), pkg, userId);
            grantUriLocked(intent.getData(), primaryClipUid, pkg, userId);
        }
        }
    }
    }


@@ -524,7 +557,8 @@ public class ClipboardService extends SystemService {
        if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
        if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
            final int N = clipboard.primaryClip.getItemCount();
            final int N = clipboard.primaryClip.getItemCount();
            for (int i=0; i<N; i++) {
            for (int i=0; i<N; i++) {
                grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid));
                grantItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid, pkg,
                        UserHandle.getUserId(uid));
            }
            }
            clipboard.activePermissionOwners.add(pkg);
            clipboard.activePermissionOwners.add(pkg);
        }
        }