Merge "Clipboard service keeps separate clipboards per user."
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 2e2a278..8a6a550 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -18,12 +18,14 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -37,6 +39,7 @@
import android.os.UserId;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import java.util.HashSet;
@@ -44,18 +47,31 @@
* Implementation of the clipboard for copy and paste.
*/
public class ClipboardService extends IClipboard.Stub {
+
+ private static final String TAG = "ClipboardService";
+
private final Context mContext;
private final IActivityManager mAm;
private final PackageManager mPm;
private final IBinder mPermissionOwner;
- private final RemoteCallbackList<IOnPrimaryClipChangedListener> mPrimaryClipListeners
- = new RemoteCallbackList<IOnPrimaryClipChangedListener>();
+ private class PerUserClipboard {
+ final int userId;
- private ClipData mPrimaryClip;
+ final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
+ = new RemoteCallbackList<IOnPrimaryClipChangedListener>();
- private final HashSet<String> mActivePermissionOwners
- = new HashSet<String>();
+ ClipData primaryClip;
+
+ final HashSet<String> activePermissionOwners
+ = new HashSet<String>();
+
+ PerUserClipboard(int userId) {
+ this.userId = userId;
+ }
+ }
+
+ private SparseArray<PerUserClipboard> mClipboards = new SparseArray<PerUserClipboard>();
/**
* Instantiates the clipboard.
@@ -71,6 +87,19 @@
Slog.w("clipboard", "AM dead", e);
}
mPermissionOwner = permOwner;
+
+ // Remove the clipboard if a user is removed
+ IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ removeClipboard(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+ }
+ }
+ }, userFilter);
}
@Override
@@ -85,6 +114,28 @@
}
+ private PerUserClipboard getClipboard() {
+ return getClipboard(UserId.getCallingUserId());
+ }
+
+ private PerUserClipboard getClipboard(int userId) {
+ synchronized (mClipboards) {
+ Slog.i(TAG, "Got clipboard for user=" + userId);
+ PerUserClipboard puc = mClipboards.get(userId);
+ if (puc == null) {
+ puc = new PerUserClipboard(userId);
+ mClipboards.put(userId, puc);
+ }
+ return puc;
+ }
+ }
+
+ private void removeClipboard(int userId) {
+ synchronized (mClipboards) {
+ mClipboards.remove(userId);
+ }
+ }
+
public void setPrimaryClip(ClipData clip) {
synchronized (this) {
if (clip != null && clip.getItemCount() <= 0) {
@@ -92,56 +143,59 @@
}
checkDataOwnerLocked(clip, Binder.getCallingUid());
clearActiveOwnersLocked();
- mPrimaryClip = clip;
- final int n = mPrimaryClipListeners.beginBroadcast();
+ PerUserClipboard clipboard = getClipboard();
+ clipboard.primaryClip = clip;
+ final int n = clipboard.primaryClipListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
- mPrimaryClipListeners.getBroadcastItem(i).dispatchPrimaryClipChanged();
+ clipboard.primaryClipListeners.getBroadcastItem(i).dispatchPrimaryClipChanged();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
- mPrimaryClipListeners.finishBroadcast();
+ clipboard.primaryClipListeners.finishBroadcast();
}
}
public ClipData getPrimaryClip(String pkg) {
synchronized (this) {
addActiveOwnerLocked(Binder.getCallingUid(), pkg);
- return mPrimaryClip;
+ return getClipboard().primaryClip;
}
}
public ClipDescription getPrimaryClipDescription() {
synchronized (this) {
- return mPrimaryClip != null ? mPrimaryClip.getDescription() : null;
+ PerUserClipboard clipboard = getClipboard();
+ return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
}
}
public boolean hasPrimaryClip() {
synchronized (this) {
- return mPrimaryClip != null;
+ return getClipboard().primaryClip != null;
}
}
public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
synchronized (this) {
- mPrimaryClipListeners.register(listener);
+ getClipboard().primaryClipListeners.register(listener);
}
}
public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
synchronized (this) {
- mPrimaryClipListeners.unregister(listener);
+ getClipboard().primaryClipListeners.unregister(listener);
}
}
public boolean hasClipboardText() {
synchronized (this) {
- if (mPrimaryClip != null) {
- CharSequence text = mPrimaryClip.getItemAt(0).getText();
+ PerUserClipboard clipboard = getClipboard();
+ if (clipboard.primaryClip != null) {
+ CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
return text != null && text.length() > 0;
}
return false;
@@ -153,7 +207,6 @@
return;
}
long ident = Binder.clearCallingIdentity();
- boolean allowed = false;
try {
// This will throw SecurityException for us.
mAm.checkGrantUriPermission(uid, null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -212,12 +265,13 @@
} catch (NameNotFoundException e) {
throw new IllegalArgumentException("Unknown package " + pkg, e);
}
- if (mPrimaryClip != null && !mActivePermissionOwners.contains(pkg)) {
- final int N = mPrimaryClip.getItemCount();
+ PerUserClipboard clipboard = getClipboard();
+ if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
+ final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
- grantItemLocked(mPrimaryClip.getItemAt(i), pkg);
+ grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg);
}
- mActivePermissionOwners.add(pkg);
+ clipboard.activePermissionOwners.add(pkg);
}
}
@@ -244,13 +298,14 @@
}
private final void clearActiveOwnersLocked() {
- mActivePermissionOwners.clear();
- if (mPrimaryClip == null) {
+ PerUserClipboard clipboard = getClipboard();
+ clipboard.activePermissionOwners.clear();
+ if (clipboard.primaryClip == null) {
return;
}
- final int N = mPrimaryClip.getItemCount();
+ final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
- revokeItemLocked(mPrimaryClip.getItemAt(i));
+ revokeItemLocked(clipboard.primaryClip.getItemAt(i));
}
}
}