AccessibilityShortcutController.java revision 33d6c08aa605bda7141ae987af0b6a8eb9329161
1106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver/*
2106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * Copyright (C) 2012 Google Inc.
3106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver *
4106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * use this file except in compliance with the License. You may obtain a copy of
6106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * the License at
7106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver *
8106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * http://www.apache.org/licenses/LICENSE-2.0
9106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver *
10106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * Unless required by applicable law or agreed to in writing, software
11106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * License for the specific language governing permissions and limitations under
14106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * the License.
15106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver */
16106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
17106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverpackage com.android.server.policy;
18106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
19106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.accessibilityservice.AccessibilityServiceInfo;
20106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.app.ActivityManager;
21106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.app.AlertDialog;
22106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.ComponentName;
23106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.ContentResolver;
24106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.Context;
25106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.DialogInterface;
26106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.database.ContentObserver;
27106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.AudioAttributes;
28106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.Ringtone;
29106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.RingtoneManager;
30ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaverimport android.net.Uri;
31106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.os.Handler;
32106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.os.UserHandle;
3332ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaverimport android.os.Vibrator;
34106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.provider.Settings;
35106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.text.TextUtils;
36106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.util.Slog;
37106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.Window;
38106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.WindowManager;
39106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.accessibility.AccessibilityManager;
40106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
41106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.widget.Toast;
42106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport com.android.internal.R;
43106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
44106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport java.util.List;
45106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
46106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
47106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
48106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver/**
49106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * Class to help manage the accessibility shortcut
50106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver */
51106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverpublic class AccessibilityShortcutController {
52106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private static final String TAG = "AccessibilityShortcutController";
5332ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
5432ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
5532ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
5632ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .build();
5732ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
58106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
59106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private final Context mContext;
60106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AlertDialog mAlertDialog;
61106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private boolean mIsShortcutEnabled;
62ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    private boolean mEnabledOnLockScreen;
63ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    private int mUserId;
64ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver
65106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    // Visible for testing
66106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
67106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
68106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public static String getTargetServiceComponentNameString(
69106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Context context, int userId) {
70106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
71106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
72106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                userId);
73106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (currentShortcutServiceId != null) {
74106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return currentShortcutServiceId;
75106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
76106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return context.getString(R.string.config_defaultAccessibilityService);
77106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
78106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
79ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
80106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        mContext = context;
81f287180de8666112cdb45c7e4f03ce397be69ec9Phil Weaver        mUserId = initialUserId;
82106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
83ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        // Keep track of state of shortcut settings
84ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final ContentObserver co = new ContentObserver(handler) {
85ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            @Override
86ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            public void onChange(boolean selfChange, Uri uri, int userId) {
87ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                if (userId == mUserId) {
88ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                    onSettingsChanged();
89ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                }
90ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            }
91ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        };
92106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        mContext.getContentResolver().registerContentObserver(
93106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
94ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
95ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mContext.getContentResolver().registerContentObserver(
96ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
97ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
98ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mContext.getContentResolver().registerContentObserver(
99ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
100ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
101ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        setCurrentUser(mUserId);
102106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
103106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
104ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public void setCurrentUser(int currentUserId) {
105ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mUserId = currentUserId;
106ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        onSettingsChanged();
107ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    }
108ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver
109ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    /**
110ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * Check if the shortcut is available.
111ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     *
112ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * @param onLockScreen Whether or not the phone is currently locked.
113ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     *
114ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * @return {@code true} if the shortcut is available
115ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     */
116ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public boolean isAccessibilityShortcutAvailable(boolean phoneLocked) {
117ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        return mIsShortcutEnabled && (!phoneLocked || mEnabledOnLockScreen);
118106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
119106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
120106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public void onSettingsChanged() {
121ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final boolean haveValidService =
122ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                !TextUtils.isEmpty(getTargetServiceComponentNameString(mContext, mUserId));
123ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final ContentResolver cr = mContext.getContentResolver();
124ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final boolean enabled = Settings.Secure.getIntForUser(
125ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
126ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mEnabledOnLockScreen = Settings.Secure.getIntForUser(
127ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0, mUserId) == 1;
128ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mIsShortcutEnabled = enabled && haveValidService;
129106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
130106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
131106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    /**
132106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver     * Called when the accessibility shortcut is activated
133106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver     */
134106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public void performAccessibilityShortcut() {
135106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        Slog.d(TAG, "Accessibility shortcut activated");
136106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final ContentResolver cr = mContext.getContentResolver();
137106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final int userId = ActivityManager.getCurrentUser();
138106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final int dialogAlreadyShown = Settings.Secure.getIntForUser(
139106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
14032ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
14132ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        // Play a notification tone
142106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final Ringtone tone =
143106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
144106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (tone != null) {
145106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            tone.setAudioAttributes(new AudioAttributes.Builder()
146106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
147106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .build());
148106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            tone.play();
149106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
15032ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
15132ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        // Play a notification vibration
15232ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
15332ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        if ((vibrator != null) && vibrator.hasVibrator()) {
15432ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            // Don't check if haptics are disabled, as we need to alert the user that their
15532ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            // way of interacting with the phone may change if they activate the shortcut
15632ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(),
15733d6c08aa605bda7141ae987af0b6a8eb9329161Michael Wright                    R.array.config_longPressVibePattern);
15832ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
15932ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        }
16032ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
16132ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
162106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (dialogAlreadyShown == 0) {
163106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // The first time, we show a warning rather than toggle the service to give the user a
164106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // chance to turn off this feature before stuff gets enabled.
165106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mAlertDialog = createShortcutWarningDialog(userId);
166106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (mAlertDialog == null) {
167106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                return;
168106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
169106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Window w = mAlertDialog.getWindow();
170106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            WindowManager.LayoutParams attr = w.getAttributes();
171106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            attr.type = TYPE_KEYGUARD_DIALOG;
172106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            w.setAttributes(attr);
173106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mAlertDialog.show();
174106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Settings.Secure.putIntForUser(
175106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
176106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        } else {
177106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (mAlertDialog != null) {
178106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mAlertDialog.dismiss();
179106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mAlertDialog = null;
180106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
181106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
182106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // Show a toast alerting the user to what's happening
183106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
184106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (serviceInfo == null) {
185106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                Slog.e(TAG, "Accessibility shortcut set to invalid service");
186106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                return;
187106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
188106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
189106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    ? R.string.accessibility_shortcut_disabling_service
190106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    : R.string.accessibility_shortcut_enabling_service);
191106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            String toastMessage = String.format(toastMessageFormatString,
192106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    serviceInfo.getResolveInfo()
193106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                            .loadLabel(mContext.getPackageManager()).toString());
1947192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
1957192297bc9669f3705d2a18893889e9a113a342aPhil Weaver                    mContext, toastMessage, Toast.LENGTH_LONG);
1967192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            warningToast.getWindowParams().privateFlags |=
1977192297bc9669f3705d2a18893889e9a113a342aPhil Weaver                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1987192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            warningToast.show();
199106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
200106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
201106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    .performAccessibilityShortcut();
202106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
203106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
204106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
205106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AlertDialog createShortcutWarningDialog(int userId) {
206106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
207106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
208106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (serviceInfo == null) {
209106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return null;
210106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
211106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
212106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String warningMessage = String.format(
213106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mContext.getString(R.string.accessibility_shortcut_toogle_warning),
214106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString());
215106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(mContext)
216106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setTitle(R.string.accessibility_shortcut_warning_dialog_title)
217106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setMessage(warningMessage)
218106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setCancelable(false)
219106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setPositiveButton(R.string.leave_accessibility_shortcut_on, null)
220106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setNegativeButton(R.string.disable_accessibility_shortcut,
221106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        (DialogInterface d, int which) -> {
222106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                            Settings.Secure.putStringForUser(mContext.getContentResolver(),
223106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
224106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                                    userId);
225106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        })
226106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setOnCancelListener((DialogInterface d) -> {
227106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    // If canceled, treat as if the dialog has never been shown
228106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
229106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
230106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                })
231106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .create();
232106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return alertDialog;
233106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
234106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
235106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AccessibilityServiceInfo getInfoForTargetService() {
236106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String currentShortcutServiceString = getTargetServiceComponentNameString(
23711b70f8834cd7a89cbdce3c5861215fd2c79f186Phil Weaver                mContext, UserHandle.USER_CURRENT);
238106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (currentShortcutServiceString == null) {
239106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return null;
240106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
241106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        AccessibilityManager accessibilityManager =
242106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
243106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return accessibilityManager.getInstalledServiceInfoWithComponentName(
244106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        ComponentName.unflattenFromString(currentShortcutServiceString));
245106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
246106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
247106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) {
248106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        AccessibilityManager accessibilityManager =
249106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
250106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return accessibilityManager.getEnabledAccessibilityServiceList(
251106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                AccessibilityServiceInfo.FEEDBACK_ALL_MASK).contains(serviceInfo);
252106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
253106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
254106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    // Class to allow mocking of static framework calls
255106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public static class FrameworkObjectProvider {
256106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public AccessibilityManager getAccessibilityManagerInstance(Context context) {
257106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return AccessibilityManager.getInstance(context);
258106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
259106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
260106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public AlertDialog.Builder getAlertDialogBuilder(Context context) {
261106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return new AlertDialog.Builder(context);
262106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
263106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
264106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
265106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return Toast.makeText(context, charSequence, duration);
266106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
267106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
268106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver}
269