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