diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 6a109253a27c8..dfd91b9a05c1b 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -124,7 +124,7 @@ public final class AccessibilityManager { * Activity action: Launch UI to manage which accessibility service or feature is assigned * to the navigation bar Accessibility button. *

- * Input: {@link #EXTRA_SHORTCUT_TYPE} is the shortcut type. + * Input: Nothing. *

*

* Output: Nothing. @@ -137,16 +137,7 @@ public final class AccessibilityManager { "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON"; /** - * Used as an int extra field in {@link #ACTION_CHOOSE_ACCESSIBILITY_BUTTON} intent to specify - * the shortcut type. - * - * @hide - */ - public static final String EXTRA_SHORTCUT_TYPE = - "com.android.internal.intent.extra.SHORTCUT_TYPE"; - - /** - * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent the accessibility button + * Used as an int value for accessibility chooser activity to represent the accessibility button * shortcut type. * * @hide @@ -154,7 +145,7 @@ public final class AccessibilityManager { public static final int ACCESSIBILITY_BUTTON = 0; /** - * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent hardware key shortcut, + * Used as an int value for accessibility chooser activity to represent hardware key shortcut, * such as volume key button. * * @hide diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java index 7c9c51c2842ff..e6360048706bc 100644 --- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -27,6 +27,11 @@ import java.lang.annotation.RetentionPolicy; public final class ShortcutConstants { private ShortcutConstants() {} + /** + * Package name of the accessibility chooser and used for {@link android.content.Intent}. + */ + public static final String CHOOSER_PACKAGE_NAME = "android"; + public static final char SERVICES_SEPARATOR = ':'; /** diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java new file mode 100644 index 0000000000000..7c4df52d14950 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.accessibility.dialog; + +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; + +import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; + +import android.annotation.Nullable; +import android.app.Activity; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.View; +import android.view.accessibility.AccessibilityManager; +import android.widget.GridView; +import android.widget.TextView; + +import com.android.internal.R; +import com.android.internal.widget.ResolverDrawerLayout; + +import java.util.ArrayList; +import java.util.List; + +/** + * Activity used to display and persist a service or feature target for the Accessibility button. + */ +public class AccessibilityButtonChooserActivity extends Activity { + private final List mTargets = new ArrayList<>(); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.accessibility_button_chooser); + + final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); + if (rdl != null) { + rdl.setOnDismissedListener(this::finish); + } + + final String component = Settings.Secure.getString(getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); + + final AccessibilityManager accessibilityManager = + getSystemService(AccessibilityManager.class); + final boolean isTouchExploreOn = + accessibilityManager.isTouchExplorationEnabled(); + final boolean isGestureNavigateEnabled = + NAV_BAR_MODE_GESTURAL == getResources().getInteger( + com.android.internal.R.integer.config_navBarInteractionMode); + + if (isGestureNavigateEnabled) { + final TextView promptPrologue = findViewById(R.id.accessibility_button_prompt_prologue); + promptPrologue.setText(isTouchExploreOn + ? R.string.accessibility_gesture_3finger_prompt_text + : R.string.accessibility_gesture_prompt_text); + } + + if (TextUtils.isEmpty(component)) { + final TextView prompt = findViewById(R.id.accessibility_button_prompt); + if (isGestureNavigateEnabled) { + prompt.setText(isTouchExploreOn + ? R.string.accessibility_gesture_3finger_instructional_text + : R.string.accessibility_gesture_instructional_text); + } + prompt.setVisibility(View.VISIBLE); + } + + mTargets.addAll(getTargets(this, ACCESSIBILITY_BUTTON)); + + final GridView gridview = findViewById(R.id.accessibility_button_chooser_grid); + gridview.setAdapter(new ButtonTargetAdapter(mTargets)); + gridview.setOnItemClickListener((parent, view, position, id) -> { + final String key = Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; + Settings.Secure.putString(getContentResolver(), key, mTargets.get(position).getId()); + finish(); + }); + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java index e8d2813fe39ed..1b7517840650c 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java @@ -23,7 +23,6 @@ import static com.android.internal.accessibility.common.ShortcutConstants.Shortc import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView; import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets; import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; -import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.Nullable; import android.app.Activity; @@ -33,7 +32,6 @@ import android.content.res.TypedArray; import android.os.Bundle; import android.view.View; import android.view.Window; -import android.view.accessibility.AccessibilityManager; import android.widget.AdapterView; import com.android.internal.R; @@ -47,7 +45,7 @@ import java.util.List; */ public class AccessibilityShortcutChooserActivity extends Activity { @ShortcutType - private int mShortcutType; + private final int mShortcutType = ACCESSIBILITY_SHORTCUT_KEY; private final List mTargets = new ArrayList<>(); private AlertDialog mMenuDialog; private AlertDialog mPermissionDialog; @@ -62,12 +60,6 @@ public class AccessibilityShortcutChooserActivity extends Activity { requestWindowFeature(Window.FEATURE_NO_TITLE); } - mShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE, - /* unexpectedShortcutType */ -1); - final boolean existInShortcutType = (mShortcutType == ACCESSIBILITY_BUTTON) - || (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY); - checkArgument(existInShortcutType, "Unexpected shortcut type: " + mShortcutType); - mTargets.addAll(getTargets(this, mShortcutType)); final String selectDialogTitle = @@ -149,10 +141,10 @@ public class AccessibilityShortcutChooserActivity extends Activity { private void updateDialogListeners() { final boolean isEditMenuMode = - (mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT); + mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT; final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title; final int editDialogTitleId = - (mShortcutType == ACCESSIBILITY_BUTTON) + mShortcutType == ACCESSIBILITY_BUTTON ? R.string.accessibility_edit_shortcut_menu_button_title : R.string.accessibility_edit_shortcut_menu_volume_title; diff --git a/core/java/com/android/internal/accessibility/dialog/ButtonTargetAdapter.java b/core/java/com/android/internal/accessibility/dialog/ButtonTargetAdapter.java new file mode 100644 index 0000000000000..9f472ac4dcdb8 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/ButtonTargetAdapter.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.accessibility.dialog; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.R; + +import java.util.List; + +/** + * Extension for {@link TargetAdapter} and used for AccessibilityButtonChooserActivity. + */ +class ButtonTargetAdapter extends TargetAdapter { + private List mTargets; + + ButtonTargetAdapter(List targets) { + mTargets = targets; + } + + @Override + public int getCount() { + return mTargets.size(); + } + + @Override + public Object getItem(int position) { + return mTargets.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final Context context = parent.getContext(); + final View root = LayoutInflater.from(context).inflate( + R.layout.accessibility_button_chooser_item, parent, /* attachToRoot= */ + false); + final AccessibilityTarget target = mTargets.get(position); + final ImageView iconView = root.findViewById(R.id.accessibility_button_target_icon); + final TextView labelView = root.findViewById(R.id.accessibility_button_target_label); + iconView.setImageDrawable(target.getIcon()); + labelView.setText(target.getLabel()); + return root; + } +} diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java index c338a292646bc..100422f5660df 100644 --- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -151,7 +151,7 @@ public final class ShortcutUtils { public static String convertToKey(@UserShortcutType int type) { switch (type) { case UserShortcutType.SOFTWARE: - return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; + return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; case UserShortcutType.HARDWARE: return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; case UserShortcutType.TRIPLETAP: diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ee25ac27b25c7..363c37b9e203f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5077,6 +5077,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml new file mode 100644 index 0000000000000..33d6fa2862f76 --- /dev/null +++ b/core/res/res/layout/accessibility_button_chooser_item.xml @@ -0,0 +1,53 @@ + + + + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5f93506d7ba2b..431549713f44d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3241,6 +3241,18 @@ + + + + + + + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index fecb7b6020129..2c0ba605f2955 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; @@ -59,6 +60,7 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.accessibility.AccessibilityManager; +import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.ScreenshotHelper; import com.android.systemui.Dumpable; @@ -354,10 +356,11 @@ public class OverviewProxyService implements CallbackController