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;
218c58d45d573fcc01557c068070d65002bc94d6d7Phil Weaverimport android.app.ActivityThread;
22106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.app.AlertDialog;
23106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.ComponentName;
24106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.ContentResolver;
25106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.Context;
26106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.content.DialogInterface;
2762e54c2e3a174c7c4b371f27694afd50424031cfZhen Sunimport android.content.pm.PackageManager;
28106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.database.ContentObserver;
29106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.AudioAttributes;
30106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.Ringtone;
31106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.media.RingtoneManager;
32ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaverimport android.net.Uri;
33106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.os.Handler;
34106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.os.UserHandle;
3532ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaverimport android.os.Vibrator;
36106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.provider.Settings;
37106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.text.TextUtils;
38106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.util.Slog;
39106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.Window;
40106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.WindowManager;
41106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.view.accessibility.AccessibilityManager;
42106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
43106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport android.widget.Toast;
44106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport com.android.internal.R;
45106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
46106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport java.util.List;
47106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
48106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverimport static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
49106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
50106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver/**
51106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver * Class to help manage the accessibility shortcut
52106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver */
53106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaverpublic class AccessibilityShortcutController {
54106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private static final String TAG = "AccessibilityShortcutController";
5532ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
5632ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
5732ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
5832ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            .build();
5932ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
60106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
61106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private final Context mContext;
62106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AlertDialog mAlertDialog;
63106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private boolean mIsShortcutEnabled;
64ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    private boolean mEnabledOnLockScreen;
65ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    private int mUserId;
66ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver
67106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    // Visible for testing
68106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
69106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
70106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public static String getTargetServiceComponentNameString(
71106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Context context, int userId) {
72106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
73106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
74106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                userId);
75106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (currentShortcutServiceId != null) {
76106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return currentShortcutServiceId;
77106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
78106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return context.getString(R.string.config_defaultAccessibilityService);
79106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
80106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
81ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
82106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        mContext = context;
83f287180de8666112cdb45c7e4f03ce397be69ec9Phil Weaver        mUserId = initialUserId;
84106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
85ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        // Keep track of state of shortcut settings
86ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final ContentObserver co = new ContentObserver(handler) {
87ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            @Override
88ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            public void onChange(boolean selfChange, Uri uri, int userId) {
89ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                if (userId == mUserId) {
90ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                    onSettingsChanged();
91ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                }
92ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver            }
93ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        };
94106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        mContext.getContentResolver().registerContentObserver(
95106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
96ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
97ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mContext.getContentResolver().registerContentObserver(
98ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
99ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
100ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mContext.getContentResolver().registerContentObserver(
101ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
102ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                false, co, UserHandle.USER_ALL);
103ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        setCurrentUser(mUserId);
104106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
105106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
106ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public void setCurrentUser(int currentUserId) {
107ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mUserId = currentUserId;
108ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        onSettingsChanged();
109ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    }
110ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver
111ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    /**
112ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * Check if the shortcut is available.
113ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     *
114ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * @param onLockScreen Whether or not the phone is currently locked.
115ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     *
116ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     * @return {@code true} if the shortcut is available
117ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver     */
118ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver    public boolean isAccessibilityShortcutAvailable(boolean phoneLocked) {
119ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        return mIsShortcutEnabled && (!phoneLocked || mEnabledOnLockScreen);
120106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
121106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
122106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public void onSettingsChanged() {
123ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final boolean haveValidService =
124ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                !TextUtils.isEmpty(getTargetServiceComponentNameString(mContext, mUserId));
125ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final ContentResolver cr = mContext.getContentResolver();
126ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        final boolean enabled = Settings.Secure.getIntForUser(
127ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
128ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mEnabledOnLockScreen = Settings.Secure.getIntForUser(
129ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0, mUserId) == 1;
130ce687c5e4a0ce27e9190fb5c823ec4649fbc3712Phil Weaver        mIsShortcutEnabled = enabled && haveValidService;
131106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
132106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
133106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    /**
134106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver     * Called when the accessibility shortcut is activated
135106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver     */
136106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public void performAccessibilityShortcut() {
137106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        Slog.d(TAG, "Accessibility shortcut activated");
138106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final ContentResolver cr = mContext.getContentResolver();
139106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final int userId = ActivityManager.getCurrentUser();
140106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final int dialogAlreadyShown = Settings.Secure.getIntForUser(
141106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
14262e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun        // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
14362e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun        // have less ways of providing feedback like vibration.
14462e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun        final int audioAttributesUsage = hasFeatureLeanback()
14562e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun                ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
14662e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun                : AudioAttributes.USAGE_NOTIFICATION_EVENT;
14732ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
14832ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        // Play a notification tone
149106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final Ringtone tone =
150106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
151106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (tone != null) {
152106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            tone.setAudioAttributes(new AudioAttributes.Builder()
15362e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun                .setUsage(audioAttributesUsage)
154106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .build());
155106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            tone.play();
156106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
15732ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
15832ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        // Play a notification vibration
15932ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
16032ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        if ((vibrator != null) && vibrator.hasVibrator()) {
16132ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            // Don't check if haptics are disabled, as we need to alert the user that their
16232ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            // way of interacting with the phone may change if they activate the shortcut
16332ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(),
16433d6c08aa605bda7141ae987af0b6a8eb9329161Michael Wright                    R.array.config_longPressVibePattern);
16532ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver            vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
16632ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver        }
16732ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
16832ea37255dbb9c5d7d40b73e435d12df934a803aPhil Weaver
169106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (dialogAlreadyShown == 0) {
170106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // The first time, we show a warning rather than toggle the service to give the user a
171106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // chance to turn off this feature before stuff gets enabled.
172106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mAlertDialog = createShortcutWarningDialog(userId);
173106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (mAlertDialog == null) {
174106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                return;
175106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
176106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Window w = mAlertDialog.getWindow();
177106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            WindowManager.LayoutParams attr = w.getAttributes();
178106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            attr.type = TYPE_KEYGUARD_DIALOG;
179106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            w.setAttributes(attr);
180106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mAlertDialog.show();
181106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            Settings.Secure.putIntForUser(
182106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
183106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        } else {
184106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (mAlertDialog != null) {
185106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mAlertDialog.dismiss();
186106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mAlertDialog = null;
187106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
188106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
189106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            // Show a toast alerting the user to what's happening
190106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
191106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            if (serviceInfo == null) {
192106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                Slog.e(TAG, "Accessibility shortcut set to invalid service");
193106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                return;
194106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            }
195106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
196106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    ? R.string.accessibility_shortcut_disabling_service
197106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    : R.string.accessibility_shortcut_enabling_service);
198106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            String toastMessage = String.format(toastMessageFormatString,
199106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    serviceInfo.getResolveInfo()
200106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                            .loadLabel(mContext.getPackageManager()).toString());
2017192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            Toast warningToast = mFrameworkObjectProvider.makeToastFromText(
2027192297bc9669f3705d2a18893889e9a113a342aPhil Weaver                    mContext, toastMessage, Toast.LENGTH_LONG);
2037192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            warningToast.getWindowParams().privateFlags |=
2047192297bc9669f3705d2a18893889e9a113a342aPhil Weaver                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2057192297bc9669f3705d2a18893889e9a113a342aPhil Weaver            warningToast.show();
206106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
207106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
208106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    .performAccessibilityShortcut();
209106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
210106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
211106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
212106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AlertDialog createShortcutWarningDialog(int userId) {
213106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
214106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
215106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (serviceInfo == null) {
216106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return null;
217106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
218106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
219106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String warningMessage = String.format(
220106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mContext.getString(R.string.accessibility_shortcut_toogle_warning),
221106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString());
2228c58d45d573fcc01557c068070d65002bc94d6d7Phil Weaver        final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(
2238c58d45d573fcc01557c068070d65002bc94d6d7Phil Weaver                // Use SystemUI context so we pick up any theme set in a vendor overlay
2248c58d45d573fcc01557c068070d65002bc94d6d7Phil Weaver                ActivityThread.currentActivityThread().getSystemUiContext())
225106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setTitle(R.string.accessibility_shortcut_warning_dialog_title)
226106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setMessage(warningMessage)
227106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setCancelable(false)
228106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setPositiveButton(R.string.leave_accessibility_shortcut_on, null)
229106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setNegativeButton(R.string.disable_accessibility_shortcut,
230106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        (DialogInterface d, int which) -> {
231106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                            Settings.Secure.putStringForUser(mContext.getContentResolver(),
232106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
233106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                                    userId);
234106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        })
235106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .setOnCancelListener((DialogInterface d) -> {
236106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    // If canceled, treat as if the dialog has never been shown
237106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
238106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
239106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                })
240106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                .create();
241106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return alertDialog;
242106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
243106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
244106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private AccessibilityServiceInfo getInfoForTargetService() {
245106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        final String currentShortcutServiceString = getTargetServiceComponentNameString(
24611b70f8834cd7a89cbdce3c5861215fd2c79f186Phil Weaver                mContext, UserHandle.USER_CURRENT);
247106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        if (currentShortcutServiceString == null) {
248106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return null;
249106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
250106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        AccessibilityManager accessibilityManager =
251106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
252106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return accessibilityManager.getInstalledServiceInfoWithComponentName(
253106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                        ComponentName.unflattenFromString(currentShortcutServiceString));
254106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
255106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
256106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) {
257106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        AccessibilityManager accessibilityManager =
258106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
259106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        return accessibilityManager.getEnabledAccessibilityServiceList(
260106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver                AccessibilityServiceInfo.FEEDBACK_ALL_MASK).contains(serviceInfo);
261106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
262106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
26362e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun    private boolean hasFeatureLeanback() {
26462e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
26562e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun    }
26662e54c2e3a174c7c4b371f27694afd50424031cfZhen Sun
267106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    // Class to allow mocking of static framework calls
268106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    public static class FrameworkObjectProvider {
269106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public AccessibilityManager getAccessibilityManagerInstance(Context context) {
270106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return AccessibilityManager.getInstance(context);
271106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
272106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
273106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public AlertDialog.Builder getAlertDialogBuilder(Context context) {
274106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return new AlertDialog.Builder(context);
275106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
276106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver
277106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
278106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver            return Toast.makeText(context, charSequence, duration);
279106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver        }
280106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver    }
281106fe732050f3d75a08c3bc48fdbcf84cac20b41Phil Weaver}
282