1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.accessibility.dialog; 17 18 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; 19 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; 20 import static android.view.accessibility.AccessibilityManager.ShortcutType; 21 22 import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; 23 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView; 24 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets; 25 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; 26 import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted; 27 28 import android.annotation.Nullable; 29 import android.app.Activity; 30 import android.app.AlertDialog; 31 import android.content.DialogInterface; 32 import android.content.res.TypedArray; 33 import android.os.Bundle; 34 import android.view.View; 35 import android.view.Window; 36 import android.widget.AdapterView; 37 38 import com.android.internal.R; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Activity used to display various targets related to accessibility service, accessibility 45 * activity or allowlisting feature for volume key shortcut. 46 */ 47 public class AccessibilityShortcutChooserActivity extends Activity { 48 @ShortcutType 49 private final int mShortcutType = ACCESSIBILITY_SHORTCUT_KEY; 50 private static final String KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE = 51 "accessibility_shortcut_menu_mode"; 52 private final List<AccessibilityTarget> mTargets = new ArrayList<>(); 53 private AlertDialog mMenuDialog; 54 private AlertDialog mPermissionDialog; 55 private ShortcutTargetAdapter mTargetAdapter; 56 57 @Override onCreate(@ullable Bundle savedInstanceState)58 protected void onCreate(@Nullable Bundle savedInstanceState) { 59 super.onCreate(savedInstanceState); 60 61 final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme); 62 if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, /* defValue= */ false)) { 63 requestWindowFeature(Window.FEATURE_NO_TITLE); 64 } 65 66 mTargets.addAll(getTargets(this, mShortcutType)); 67 mTargetAdapter = new ShortcutTargetAdapter(mTargets); 68 mMenuDialog = createMenuDialog(); 69 mMenuDialog.setOnShowListener(dialog -> updateDialogListeners()); 70 mMenuDialog.show(); 71 72 if (savedInstanceState != null) { 73 final int restoreShortcutMenuMode = 74 savedInstanceState.getInt(KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE, 75 ShortcutMenuMode.LAUNCH); 76 if (restoreShortcutMenuMode == ShortcutMenuMode.EDIT) { 77 onEditButtonClicked(); 78 } 79 } 80 } 81 82 @Override onDestroy()83 protected void onDestroy() { 84 mMenuDialog.setOnDismissListener(null); 85 mMenuDialog.dismiss(); 86 super.onDestroy(); 87 } 88 89 @Override onSaveInstanceState(Bundle outState)90 protected void onSaveInstanceState(Bundle outState) { 91 super.onSaveInstanceState(outState); 92 outState.putInt(KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE, mTargetAdapter.getShortcutMenuMode()); 93 } 94 onTargetSelected(AdapterView<?> parent, View view, int position, long id)95 private void onTargetSelected(AdapterView<?> parent, View view, int position, long id) { 96 final AccessibilityTarget target = mTargets.get(position); 97 target.onSelected(); 98 mMenuDialog.dismiss(); 99 } 100 onTargetChecked(AdapterView<?> parent, View view, int position, long id)101 private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) { 102 final AccessibilityTarget target = mTargets.get(position); 103 104 if ((target instanceof AccessibilityServiceTarget) && !target.isShortcutEnabled()) { 105 mPermissionDialog = new AlertDialog.Builder(this) 106 .setView(createEnableDialogContentView(this, 107 (AccessibilityServiceTarget) target, 108 v -> { 109 mPermissionDialog.dismiss(); 110 mTargetAdapter.notifyDataSetChanged(); 111 }, 112 v -> mPermissionDialog.dismiss())) 113 .create(); 114 mPermissionDialog.show(); 115 return; 116 } 117 118 target.onCheckedChanged(!target.isShortcutEnabled()); 119 mTargetAdapter.notifyDataSetChanged(); 120 } 121 onDoneButtonClicked()122 private void onDoneButtonClicked() { 123 mTargets.clear(); 124 mTargets.addAll(getTargets(this, mShortcutType)); 125 if (mTargets.isEmpty()) { 126 mMenuDialog.dismiss(); 127 return; 128 } 129 130 mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH); 131 mTargetAdapter.notifyDataSetChanged(); 132 133 mMenuDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText( 134 getString(R.string.edit_accessibility_shortcut_menu_button)); 135 136 updateDialogListeners(); 137 } 138 onEditButtonClicked()139 private void onEditButtonClicked() { 140 mTargets.clear(); 141 mTargets.addAll(getInstalledTargets(this, mShortcutType)); 142 mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT); 143 mTargetAdapter.notifyDataSetChanged(); 144 145 mMenuDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText( 146 getString(R.string.done_accessibility_shortcut_menu_button)); 147 148 updateDialogListeners(); 149 } 150 updateDialogListeners()151 private void updateDialogListeners() { 152 final boolean isEditMenuMode = 153 mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT; 154 final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title; 155 final int editDialogTitleId = 156 mShortcutType == ACCESSIBILITY_BUTTON 157 ? R.string.accessibility_edit_shortcut_menu_button_title 158 : R.string.accessibility_edit_shortcut_menu_volume_title; 159 160 mMenuDialog.setTitle(getString(isEditMenuMode ? editDialogTitleId : selectDialogTitleId)); 161 mMenuDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener( 162 isEditMenuMode ? view -> onDoneButtonClicked() : view -> onEditButtonClicked()); 163 mMenuDialog.getListView().setOnItemClickListener( 164 isEditMenuMode ? this::onTargetChecked : this::onTargetSelected); 165 } 166 createMenuDialog()167 private AlertDialog createMenuDialog() { 168 final String dialogTitle = 169 getString(R.string.accessibility_select_shortcut_menu_title); 170 171 final AlertDialog.Builder builder = new AlertDialog.Builder(this) 172 .setTitle(dialogTitle) 173 .setAdapter(mTargetAdapter, /* listener= */ null) 174 .setOnDismissListener(dialog -> finish()); 175 176 if (isUserSetupCompleted(this)) { 177 final String positiveButtonText = 178 getString(R.string.edit_accessibility_shortcut_menu_button); 179 builder.setPositiveButton(positiveButtonText, /* listener= */ null); 180 } 181 182 return builder.create(); 183 } 184 } 185