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