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

Commit a3a9194e authored by Toni Barzic's avatar Toni Barzic
Browse files

Read autoclick delay from settings

Instead of hardcoding autoclick delay, use
Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY value.
Adds logic for observing the setting's changes and updating the delay
that should be used when scheduling automatical click.

BUG=23113412

Change-Id: Iffe3df0cb64ab28f13d2803d01d581280aedf422
parent 9b9da704
Loading
Loading
Loading
Loading
+103 −5
Original line number Diff line number Diff line
@@ -16,9 +16,16 @@

package com.android.server.accessibility;

import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -46,16 +53,17 @@ import android.view.accessibility.AccessibilityEvent;
 * the class should handle cases where multiple mouse devices are present.
 */
public class AutoclickController implements EventStreamTransformation {
    private static final String LOG_TAG = AutoclickController.class.getSimpleName();

    // TODO: Control click delay via settings.
    private static final int CLICK_DELAY_MS = 600;
    public static final int DEFAULT_CLICK_DELAY_MS = 600;

    private static final String LOG_TAG = AutoclickController.class.getSimpleName();

    private EventStreamTransformation mNext;
    private Context mContext;
    private final Context mContext;

    // Lazily created on the first mouse motion event.
    private ClickScheduler mClickScheduler;
    private ClickDelayObserver mClickDelayObserver;

    public AutoclickController(Context context) {
        mContext = context;
@@ -66,7 +74,9 @@ public class AutoclickController implements EventStreamTransformation {
        if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
            if (mClickScheduler == null) {
                Handler handler = new Handler(mContext.getMainLooper());
                mClickScheduler = new ClickScheduler(handler, CLICK_DELAY_MS);
                mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS);
                mClickDelayObserver = new ClickDelayObserver(handler);
                mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler);
            }

            handleMouseMotion(event, policyFlags);
@@ -119,8 +129,13 @@ public class AutoclickController implements EventStreamTransformation {

    @Override
    public void onDestroy() {
        if (mClickDelayObserver != null) {
            mClickDelayObserver.stop();
            mClickDelayObserver = null;
        }
        if (mClickScheduler != null) {
            mClickScheduler.cancel();
            mClickScheduler = null;
        }
    }

@@ -142,6 +157,80 @@ public class AutoclickController implements EventStreamTransformation {
        }
    }

    /**
     * Observes setting value for autoclick delay, and updates ClickScheduler delay whenever the
     * setting value changes.
     */
    final private static class ClickDelayObserver extends ContentObserver {
        /** URI used to identify the autoclick delay setting with content resolver. */
        private final Uri mAutoclickDelaySettingUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY);

        private ContentResolver mContentResolver;
        private ClickScheduler mClickScheduler;

        public ClickDelayObserver(Handler handler) {
            super(handler);
        }

        /**
         * Starts the observer. And makes sure up-to-date autoclick delay is propagated to
         * |clickScheduler|.
         *
         * @param contentResolver Content resolver that should be observed for setting's value
         *     changes.
         * @param clickScheduler ClickScheduler that should be updated when click delay changes.
         * @throws IllegalStateException If internal state is already setup when the method is
         *         called.
         * @throws NullPointerException If any of the arguments is a null pointer.
         */
        public void start(@NonNull ContentResolver contentResolver,
                @NonNull ClickScheduler clickScheduler) {
            if (mContentResolver != null || mClickScheduler != null) {
                throw new IllegalStateException("Observer already started.");
            }
            if (contentResolver == null) {
                throw new NullPointerException("contentResolver not set.");
            }
            if (clickScheduler == null) {
                throw new NullPointerException("clickScheduler not set.");
            }

            mContentResolver = contentResolver;
            mClickScheduler = clickScheduler;
            mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this,
                    UserHandle.USER_ALL);

            // Initialize mClickScheduler's initial delay value.
            onChange(true, mAutoclickDelaySettingUri);
        }

        /**
         * Stops the the observer. Should only be called if the observer has been started.
         *
         * @throws IllegalStateException If internal state hasn't yet been initialized by calling
         *         {@link #start}.
         */
        public void stop() {
            if (mContentResolver == null || mClickScheduler == null) {
                throw new IllegalStateException("ClickDelayObserver not started.");
            }

            mContentResolver.unregisterContentObserver(this);
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            if (mAutoclickDelaySettingUri.equals(uri)) {
                // TODO: Plumb current user id down to here and use getIntForUser.
                int delay = Settings.Secure.getInt(
                        mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
                        DEFAULT_CLICK_DELAY_MS);
                mClickScheduler.updateDelay(delay);
            }
        }
    }

    /**
     * Schedules and performs click event sequence that should be initiated when mouse pointer stops
     * moving. The click is first scheduled when a mouse movement is detected, and then further
@@ -241,6 +330,15 @@ public class AutoclickController implements EventStreamTransformation {
            mMetaState = state;
        }

        /**
         * Updates delay that should be used when scheduling clicks. The delay will be used only for
         * clicks scheduled after this point (pending click tasks are not affected).
         * @param delay New delay value.
         */
        public void updateDelay(int delay) {
            mDelay = delay;
        }

        /**
         * Updates the time at which click sequence should occur.
         *