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