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

Unverified Commit dd2b2027 authored by Michael Bestas's avatar Michael Bestas
Browse files

SUW: Remove old accessibility toggle

* This has been replaced by a different gesture in 2016

Change-Id: I86aa43f52077c1f82150eb0ddb4b59ba99005e6e
parent 070a852f
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import android.widget.ImageView;
import com.google.android.setupcompat.util.SystemBarHelper;
import com.google.android.setupcompat.util.WizardManagerHelper;

import org.lineageos.setupwizard.util.EnableAccessibilityController;
import org.lineageos.setupwizard.util.SetupWizardUtils;

import lineageos.providers.LineageSettings;
@@ -59,8 +58,6 @@ public class FinishActivity extends BaseSetupWizardActivity {

    private ImageView mReveal;

    private EnableAccessibilityController mEnableAccessibilityController;

    private SetupWizardApp mSetupWizardApp;

    private final Handler mHandler = new Handler();
@@ -75,8 +72,6 @@ public class FinishActivity extends BaseSetupWizardActivity {
        }
        mSetupWizardApp = (SetupWizardApp) getApplication();
        mReveal = (ImageView) findViewById(R.id.reveal);
        mEnableAccessibilityController =
                EnableAccessibilityController.getInstance(getApplicationContext());
        setNextText(R.string.start);
    }

@@ -174,9 +169,6 @@ public class FinishActivity extends BaseSetupWizardActivity {
    }

    private void completeSetup() {
        if (mEnableAccessibilityController != null) {
            mEnableAccessibilityController.onDestroy();
        }
        handleEnableMetrics(mSetupWizardApp);
        handleNavKeys(mSetupWizardApp);
        handleRecoveryUpdate(mSetupWizardApp);
+0 −8
Original line number Diff line number Diff line
@@ -23,14 +23,11 @@ import android.view.View;

import com.google.android.setupcompat.util.SystemBarHelper;

import org.lineageos.setupwizard.util.EnableAccessibilityController;

public class WelcomeActivity extends BaseSetupWizardActivity {

    public static final String TAG = WelcomeActivity.class.getSimpleName();

    private View mRootView;
    private EnableAccessibilityController mEnableAccessibilityController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -44,11 +41,6 @@ public class WelcomeActivity extends BaseSetupWizardActivity {
                .setOnClickListener(view -> startEmergencyDialer());
        findViewById(R.id.launch_accessibility)
                .setOnClickListener(view -> startAccessibilitySettings());
        mEnableAccessibilityController =
                EnableAccessibilityController.getInstance(getApplicationContext());
        mRootView.setOnTouchListener((v, event) ->
                mEnableAccessibilityController.onTouchEvent(event));

    }

    @Override
+0 −279
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 Google Inc.
 *
 * 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 org.lineageos.setupwizard.util;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserManager;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.util.MathUtils;
import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;

import com.android.internal.R;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class EnableAccessibilityController {

    private static final int SPEAK_WARNING_DELAY_MILLIS = 5000;
    private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 12000;

    public static final int MESSAGE_SPEAK_WARNING = 1;
    public static final int MESSAGE_SPEAK_ENABLE_CANCELED = 2;
    public static final int MESSAGE_ENABLE_ACCESSIBILITY = 3;

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MESSAGE_SPEAK_WARNING: {
                    // TODO: Fix these or remove these
                    //String text = mContext.getString(R.string.continue_to_enable_accessibility);
                    //mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
                }
                break;
                case MESSAGE_SPEAK_ENABLE_CANCELED: {
                    //String text = mContext.getString(R.string.enable_accessibility_canceled);
                    //mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
                }
                break;
                case MESSAGE_ENABLE_ACCESSIBILITY: {
                    enableAccessibility();
                    //mTone.play();
                    //mTts.speak(mContext.getString(R.string.accessibility_enabled),
                    //        TextToSpeech.QUEUE_FLUSH, null);
                }
                break;
            }
        }
    };

    private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
            ServiceManager.getService("window"));

    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
            .Stub.asInterface(ServiceManager.getService("accessibility"));

    private final Context mContext;
    private final UserManager mUserManager;
    private final TextToSpeech mTts;
    private final Ringtone mTone;

    private final float mTouchSlop;

    private boolean mDestroyed;

    private float mFirstPointerDownX;
    private float mFirstPointerDownY;
    private float mSecondPointerDownX;
    private float mSecondPointerDownY;

    private static EnableAccessibilityController sInstance;

    private EnableAccessibilityController(Context context) {
        mContext = context;
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (mDestroyed) {
                    mTts.shutdown();
                }
            }
        });
        mTone = RingtoneManager.getRingtone(context, Settings.System.DEFAULT_NOTIFICATION_URI);
        mTone.setStreamType(AudioManager.STREAM_MUSIC);
        mTouchSlop = context.getResources().getDimensionPixelSize(
                R.dimen.accessibility_touch_slop);
    }

    public static EnableAccessibilityController getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new EnableAccessibilityController(context);
        }
        return sInstance;
    }

    public static boolean canEnableAccessibilityViaGesture(Context context) {
        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
        // Accessibility is enabled and there is an enabled speaking
        // accessibility service, then we have nothing to do.
        if (accessibilityManager.isEnabled()
                && !accessibilityManager.getEnabledAccessibilityServiceList(
                AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()) {
            return false;
        }

        // If there is a speaking service
        // installed we are good to go, otherwise there is nothing to do.
        return getInstalledSpeakingAccessibilityServices(context).isEmpty();
    }

    private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
            Context context) {
        List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
        services.addAll(AccessibilityManager.getInstance(context)
                .getInstalledAccessibilityServiceList());
        Iterator<AccessibilityServiceInfo> iterator = services.iterator();
        while (iterator.hasNext()) {
            AccessibilityServiceInfo service = iterator.next();
            if ((service.feedbackType & AccessibilityServiceInfo.FEEDBACK_SPOKEN) == 0) {
                iterator.remove();
            }
        }
        return services;
    }

    public void onDestroy() {
        mDestroyed = true;
    }

    public boolean onTouchEvent(MotionEvent event) {
        final int pointerCount = event.getPointerCount();
        final int action = event.getActionMasked();

        if (pointerCount != 2) {
            cancel();
            return true;
        }

        switch (action) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN: {
                mFirstPointerDownX = event.getX(0);
                mFirstPointerDownY = event.getY(0);
                mSecondPointerDownX = event.getX(1);
                mSecondPointerDownY = event.getY(1);
                mHandler.sendEmptyMessageDelayed(MESSAGE_SPEAK_WARNING,
                        SPEAK_WARNING_DELAY_MILLIS);
                mHandler.sendEmptyMessageDelayed(MESSAGE_ENABLE_ACCESSIBILITY,
                        ENABLE_ACCESSIBILITY_DELAY_MILLIS);
            }
            break;
            case MotionEvent.ACTION_MOVE: {
                final float firstPointerMove = MathUtils.dist(event.getX(0),
                        event.getY(0), mFirstPointerDownX, mFirstPointerDownY);
                if (Math.abs(firstPointerMove) > mTouchSlop) {
                    cancel();
                }
                final float secondPointerMove = MathUtils.dist(event.getX(1),
                        event.getY(1), mSecondPointerDownX, mSecondPointerDownY);
                if (Math.abs(secondPointerMove) > mTouchSlop) {
                    cancel();
                }
            }
            break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_CANCEL: {
                cancel();
            }
            break;
        }
        return true;
    }

    private void cancel() {
        if (mHandler.hasMessages(MESSAGE_SPEAK_WARNING)) {
            mHandler.removeMessages(MESSAGE_SPEAK_WARNING);
        } else if (mHandler.hasMessages(MESSAGE_ENABLE_ACCESSIBILITY)) {
            mHandler.sendEmptyMessage(MESSAGE_SPEAK_ENABLE_CANCELED);
        }
        mHandler.removeMessages(MESSAGE_ENABLE_ACCESSIBILITY);
    }

    private void enableAccessibility() {
        List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
                mContext);
        if (services.isEmpty()) {
            return;
        }
        boolean keyguardLocked = false;
        try {
            keyguardLocked = mWindowManager.isKeyguardLocked();
        } catch (RemoteException re) {
            /* ignore */
        }

        final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;

        AccessibilityServiceInfo service = services.get(0);
        boolean enableTouchExploration = (service.flags
                & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
        // Try to find a service supporting explore by touch.
        if (!enableTouchExploration) {
            final int serviceCount = services.size();
            for (int i = 1; i < serviceCount; i++) {
                AccessibilityServiceInfo candidate = services.get(i);
                if ((candidate.flags & AccessibilityServiceInfo
                        .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
                    enableTouchExploration = true;
                    service = candidate;
                    break;
                }
            }
        }

        ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
        ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
        if (!keyguardLocked || !hasMoreThanOneUser) {
            final int userId = ActivityManager.getCurrentUser();
            String enabledServiceString = componentName.flattenToString();
            ContentResolver resolver = mContext.getContentResolver();
            // Enable one speaking accessibility service.
            Settings.Secure.putStringForUser(resolver,
                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                    enabledServiceString, userId);
            // Allow the services we just enabled to toggle touch exploration.
            Settings.Secure.putStringForUser(resolver,
                    Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                    enabledServiceString, userId);
            // Enable touch exploration.
            if (enableTouchExploration) {
                Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
                        1, userId);
            }
            // Turn on accessibility mode last.
            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
                    1, userId);
        } else if (keyguardLocked) {
            try {
                mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
                        componentName, enableTouchExploration);
            } catch (RemoteException re) {
                /* ignore */
            }
        }
    }
}