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 17 package com.android.internal.accessibility.dialog; 18 19 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; 20 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; 21 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SuppressLint; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.graphics.drawable.Drawable; 29 import android.os.UserHandle; 30 import android.view.View; 31 import android.view.accessibility.AccessibilityManager; 32 33 import com.android.internal.accessibility.common.ShortcutConstants; 34 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; 35 import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; 36 import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; 37 import com.android.internal.accessibility.util.ShortcutUtils; 38 import com.android.internal.annotations.VisibleForTesting; 39 40 import java.util.Set; 41 42 /** 43 * Abstract base class for creating various target related to accessibility service, accessibility 44 * activity, and allowlisting features. 45 * 46 * <p> Disables accessibility features that are not permitted in adding a restricted padlock icon 47 * and showing admin support message dialog. 48 */ 49 public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener, 50 OnTargetCheckedChangeListener { 51 private Context mContext; 52 @UserShortcutType 53 private int mShortcutType; 54 @AccessibilityFragmentType 55 private int mFragmentType; 56 private boolean mShortcutEnabled; 57 private String mId; 58 private int mUid; 59 private ComponentName mComponentName; 60 private CharSequence mLabel; 61 private Drawable mIcon; 62 private String mKey; 63 private CharSequence mStateDescription; 64 65 @VisibleForTesting AccessibilityTarget(Context context, @UserShortcutType int shortcutType, @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon, String key)66 public AccessibilityTarget(Context context, @UserShortcutType int shortcutType, 67 @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, 68 int uid, CharSequence label, Drawable icon, String key) { 69 if (!isRecognizedShortcutType(shortcutType)) { 70 throw new IllegalArgumentException( 71 "Unexpected shortcut type " + ShortcutUtils.convertToKey(shortcutType)); 72 } 73 mContext = context; 74 mShortcutType = shortcutType; 75 mFragmentType = fragmentType; 76 mShortcutEnabled = isShortcutSwitched; 77 mId = id; 78 mUid = uid; 79 mComponentName = ComponentName.unflattenFromString(id); 80 mLabel = label; 81 mIcon = icon; 82 mKey = key; 83 } 84 85 @Override updateActionItem(@onNull ViewHolder holder, @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode)86 public void updateActionItem(@NonNull ViewHolder holder, 87 @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode) { 88 // Resetting the enable state of the item to avoid the previous wrong state of RecyclerView. 89 holder.mCheckBoxView.setEnabled(true); 90 holder.mIconView.setEnabled(true); 91 holder.mLabelView.setEnabled(true); 92 holder.mStatusView.setEnabled(true); 93 94 final boolean isEditMenuMode = 95 shortcutMenuMode == ShortcutConstants.ShortcutMenuMode.EDIT; 96 holder.mCheckBoxView.setChecked(isEditMenuMode && isShortcutEnabled()); 97 holder.mCheckBoxView.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE); 98 holder.mIconView.setImageDrawable(getIcon()); 99 holder.mLabelView.setText(getLabel()); 100 holder.mStatusView.setVisibility(View.GONE); 101 } 102 103 @SuppressLint("MissingPermission") 104 @Override onSelected()105 public void onSelected() { 106 final AccessibilityManager am = 107 getContext().getSystemService(AccessibilityManager.class); 108 if (am == null) { 109 return; 110 } 111 am.performAccessibilityShortcut(getContext().getDisplayId(), mShortcutType, getId()); 112 } 113 114 @SuppressLint("MissingPermission") 115 @Override onCheckedChanged(boolean isChecked)116 public void onCheckedChanged(boolean isChecked) { 117 setShortcutEnabled(isChecked); 118 final AccessibilityManager am = getContext().getSystemService(AccessibilityManager.class); 119 am.enableShortcutsForTargets( 120 isChecked, getShortcutType(), Set.of(mId), UserHandle.myUserId()); 121 } 122 setStateDescription(CharSequence stateDescription)123 public void setStateDescription(CharSequence stateDescription) { 124 mStateDescription = stateDescription; 125 } 126 127 /** 128 * Gets the state description of this feature target. 129 * 130 * @return the state description 131 */ 132 @Nullable getStateDescription()133 public CharSequence getStateDescription() { 134 return mStateDescription; 135 } 136 setShortcutEnabled(boolean enabled)137 public void setShortcutEnabled(boolean enabled) { 138 mShortcutEnabled = enabled; 139 } 140 getContext()141 public Context getContext() { 142 return mContext; 143 } 144 getShortcutType()145 public @UserShortcutType int getShortcutType() { 146 return mShortcutType; 147 } 148 getFragmentType()149 public @AccessibilityFragmentType int getFragmentType() { 150 return mFragmentType; 151 } 152 isShortcutEnabled()153 public boolean isShortcutEnabled() { 154 return mShortcutEnabled; 155 } 156 getId()157 public String getId() { 158 return mId; 159 } 160 getUid()161 public int getUid() { 162 return mUid; 163 } 164 getComponentName()165 public ComponentName getComponentName() { 166 return mComponentName; 167 } 168 getLabel()169 public CharSequence getLabel() { 170 return mLabel; 171 } 172 getIcon()173 public Drawable getIcon() { 174 return mIcon; 175 } 176 getKey()177 public String getKey() { 178 return mKey; 179 } 180 181 /** 182 * Determines if the provided shortcut type is valid for use with AccessibilityTargets. 183 * @param shortcutType shortcut type to check. 184 * @return {@code true} if the shortcut type can be used, {@code false} otherwise. 185 */ 186 @VisibleForTesting isRecognizedShortcutType(@serShortcutType int shortcutType)187 public static boolean isRecognizedShortcutType(@UserShortcutType int shortcutType) { 188 int mask = SOFTWARE | HARDWARE; 189 if (android.provider.Flags.a11yStandaloneGestureEnabled()) { 190 mask = mask | GESTURE; 191 } 192 return (shortcutType != 0 && (shortcutType & mask) == shortcutType); 193 } 194 } 195