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

Commit 0df805e7 authored by Ganesh Olekar's avatar Ganesh Olekar
Browse files

Clear clipboard after a defined period of inactivity

Bug: 197758448
Test: Tested manually and unit tests in CTS
Test: atest ClipboardAutoClearTest -c
Change-Id: I5ba7f01b244ef482b99976e05bddc08fde391ffe
parent 3ae9a688
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IUserManager;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -74,6 +76,8 @@ import android.widget.Toast;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
@@ -99,6 +103,22 @@ public class ClipboardService extends SystemService {
    private static final boolean IS_EMULATOR =
            SystemProperties.getBoolean("ro.boot.qemu", false);

    @VisibleForTesting
    public static final long DEFAULT_CLIPBOARD_TIMEOUT_MILLIS = 3600000;

    /**
     * Device config property for whether clipboard auto clear is enabled on the device
     **/
    public static final String PROPERTY_AUTO_CLEAR_ENABLED =
            "auto_clear_enabled";

    /**
     * Device config property for time period in milliseconds after which clipboard is auto
     * cleared
     **/
    public static final String PROPERTY_AUTO_CLEAR_TIMEOUT =
            "auto_clear_timeout";

    // DeviceConfig properties
    private static final String PROPERTY_MAX_CLASSIFICATION_LENGTH = "max_classification_length";
    private static final int DEFAULT_MAX_CLASSIFICATION_LENGTH = 400;
@@ -312,6 +332,10 @@ public class ClipboardService extends SystemService {
     * 'intendingUserId' and the uid is called 'intendingUid'.
     */
    private class ClipboardImpl extends IClipboard.Stub {

        private final Handler mClipboardClearHandler = new ClipboardClearHandler(
                mWorkerHandler.getLooper());

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                throws RemoteException {
@@ -352,10 +376,34 @@ public class ClipboardService extends SystemService {
            }
            checkDataOwner(clip, intendingUid);
            synchronized (mLock) {
                scheduleAutoClear(userId);
                setPrimaryClipInternalLocked(clip, intendingUid, sourcePackage);
            }
        }

        private void scheduleAutoClear(@UserIdInt int userId) {
            final long oldIdentity = Binder.clearCallingIdentity();
            try {
                if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
                        PROPERTY_AUTO_CLEAR_ENABLED, false)) {
                    mClipboardClearHandler.removeEqualMessages(ClipboardClearHandler.MSG_CLEAR,
                            userId);
                    Message clearMessage = Message.obtain(mClipboardClearHandler,
                            ClipboardClearHandler.MSG_CLEAR, userId, 0, userId);
                    mClipboardClearHandler.sendMessageDelayed(clearMessage,
                            getTimeoutForAutoClear());
                }
            } finally {
                Binder.restoreCallingIdentity(oldIdentity);
            }
        }

        private long getTimeoutForAutoClear() {
            return DeviceConfig.getLong(DeviceConfig.NAMESPACE_CLIPBOARD,
                    PROPERTY_AUTO_CLEAR_TIMEOUT,
                    DEFAULT_CLIPBOARD_TIMEOUT_MILLIS);
        }

        @Override
        public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) {
            final int intendingUid = getIntendingUid(callingPackage, userId);
@@ -365,6 +413,8 @@ public class ClipboardService extends SystemService {
                return;
            }
            synchronized (mLock) {
                mClipboardClearHandler.removeEqualMessages(ClipboardClearHandler.MSG_CLEAR,
                        userId);
                setPrimaryClipInternalLocked(null, intendingUid, callingPackage);
            }
        }
@@ -391,6 +441,9 @@ public class ClipboardService extends SystemService {
                PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
                showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
                notifyTextClassifierLocked(clipboard, pkg, intendingUid);
                if (clipboard.primaryClip != null) {
                    scheduleAutoClear(userId);
                }
                return clipboard.primaryClip;
            }
        }
@@ -484,6 +537,32 @@ public class ClipboardService extends SystemService {
                return null;
            }
        }

        private class ClipboardClearHandler extends Handler {

            public static final int MSG_CLEAR = 101;

            ClipboardClearHandler(Looper looper) {
                super(looper);
            }

            public void handleMessage(@NonNull Message msg) {
                switch (msg.what) {
                    case MSG_CLEAR:
                        final int userId = msg.arg1;
                        synchronized (mLock) {
                            if (getClipboardLocked(userId).primaryClip != null) {
                                FrameworkStatsLog.write(FrameworkStatsLog.CLIPBOARD_CLEARED,
                                        FrameworkStatsLog.CLIPBOARD_CLEARED__SOURCE__AUTO_CLEAR);
                                setPrimaryClipInternalLocked(null, Binder.getCallingUid(), null);
                            }
                        }
                        break;
                    default:
                        Slog.wtf(TAG, "ClipboardClearHandler received unknown message " + msg.what);
                }
            }
        }
    };

    @GuardedBy("mLock")