• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.accessibility;
18 
19 import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
20 
21 import android.accessibilityservice.AccessibilityShortcutInfo;
22 import android.app.ActivityOptions;
23 import android.content.ActivityNotFoundException;
24 import android.content.ComponentName;
25 import android.content.ContentResolver;
26 import android.content.Intent;
27 import android.content.pm.ActivityInfo;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.UserHandle;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.Menu;
35 import android.view.MenuInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.view.accessibility.AccessibilityManager;
39 
40 import androidx.annotation.Nullable;
41 import androidx.preference.Preference;
42 
43 import com.android.settings.R;
44 import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
45 
46 import java.util.ArrayList;
47 import java.util.List;
48 
49 /** Fragment for providing open activity button. */
50 public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeaturePreferenceFragment {
51 
52     private static final String TAG = "LaunchAccessibilityActivityPreferenceFragment";
53     private static final String EMPTY_STRING = "";
54     protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
55 
56     private ComponentName mTileComponentName;
57 
58     @Override
getMetricsCategory()59     public int getMetricsCategory() {
60         return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
61     }
62 
63     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)64     public View onCreateView(LayoutInflater inflater, ViewGroup container,
65             Bundle savedInstanceState) {
66         // Init new preference to replace the switch preference instead.
67         initLaunchPreference();
68 
69         final View view = super.onCreateView(inflater, container, savedInstanceState);
70         removePreference(KEY_USE_SERVICE_PREFERENCE);
71         return view;
72     }
73 
74     @Override
onPreferenceToggled(String preferenceKey, boolean enabled)75     protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
76         // Do nothing.
77     }
78 
79     @Override
onProcessArguments(Bundle arguments)80     protected void onProcessArguments(Bundle arguments) {
81         super.onProcessArguments(arguments);
82         mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
83         final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo();
84         mPackageName = info.loadLabel(getPackageManager()).toString();
85 
86         // Settings animated image.
87         final int animatedImageRes = arguments.getInt(
88                 AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES);
89         if (animatedImageRes > 0) {
90             mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
91                     .authority(mComponentName.getPackageName())
92                     .appendPath(String.valueOf(animatedImageRes))
93                     .build();
94         }
95 
96         // Settings html description.
97         mHtmlDescription = arguments.getCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION);
98 
99         // Settings title and intent.
100         final String settingsTitle = arguments.getString(
101                 AccessibilitySettings.EXTRA_SETTINGS_TITLE);
102         mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments);
103         mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle;
104 
105         // Tile service.
106         if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
107             final String tileServiceComponentName = arguments.getString(
108                     AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME);
109             mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName);
110         }
111     }
112 
113     @Override
getUserShortcutTypes()114     int getUserShortcutTypes() {
115         return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
116                 mComponentName);
117     }
118 
119     @Override
getTileComponentName()120     ComponentName getTileComponentName() {
121         return mTileComponentName;
122     }
123 
124     @Override
getTileTooltipContent(@uickSettingsTooltipType int type)125     CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
126         final ComponentName componentName = getTileComponentName();
127         if (componentName == null) {
128             return null;
129         }
130 
131         final CharSequence tileName = loadTileLabel(getPrefContext(), componentName);
132         if (tileName == null) {
133             return null;
134         }
135 
136         final int titleResId = type == QuickSettingsTooltipType.GUIDE_TO_EDIT
137                 ? R.string.accessibility_service_qs_tooltip_content
138                 : R.string.accessibility_service_auto_added_qs_tooltip_content;
139         return getString(titleResId, tileName);
140     }
141 
142     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)143     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
144         // Do not call super. We don't want to see the "Help & feedback" option on this page so as
145         // not to confuse users who think they might be able to send feedback about a specific
146         // accessibility service from this page.
147     }
148 
149     // IMPORTANT: Refresh the info since there are dynamically changing capabilities.
getAccessibilityShortcutInfo()150     private AccessibilityShortcutInfo getAccessibilityShortcutInfo() {
151         final List<AccessibilityShortcutInfo> infos = AccessibilityManager.getInstance(
152                 getPrefContext()).getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
153                 UserHandle.myUserId());
154 
155         for (int i = 0, count = infos.size(); i < count; i++) {
156             AccessibilityShortcutInfo shortcutInfo = infos.get(i);
157             ActivityInfo activityInfo = shortcutInfo.getActivityInfo();
158             if (mComponentName.getPackageName().equals(activityInfo.packageName)
159                     && mComponentName.getClassName().equals(activityInfo.name)) {
160                 return shortcutInfo;
161             }
162         }
163         return null;
164     }
165 
166     /** Customizes the order by preference key. */
getPreferenceOrderList()167     protected List<String> getPreferenceOrderList() {
168         final List<String> lists = new ArrayList<>();
169         lists.add(KEY_TOP_INTRO_PREFERENCE);
170         lists.add(KEY_ANIMATED_IMAGE);
171         lists.add(KEY_LAUNCH_PREFERENCE);
172         lists.add(KEY_GENERAL_CATEGORY);
173         lists.add(KEY_HTML_DESCRIPTION_PREFERENCE);
174         return lists;
175     }
176 
initLaunchPreference()177     private void initLaunchPreference() {
178         final Preference launchPreference = new Preference(getPrefContext());
179         launchPreference.setLayoutResource(R.layout.accessibility_launch_activity_preference);
180         launchPreference.setKey(KEY_LAUNCH_PREFERENCE);
181 
182         final AccessibilityShortcutInfo info = getAccessibilityShortcutInfo();
183         final String switchBarText = (info == null) ? EMPTY_STRING : getString(
184                 R.string.accessibility_service_primary_open_title,
185                 info.getActivityInfo().loadLabel(getPackageManager()));
186         launchPreference.setTitle(switchBarText);
187 
188         launchPreference.setOnPreferenceClickListener(preference -> {
189             logAccessibilityServiceEnabled(mComponentName, /* enabled= */ true);
190             launchShortcutTargetActivity(getPrefContext().getDisplayId(), mComponentName);
191             return true;
192         });
193         getPreferenceScreen().addPreference(launchPreference);
194     }
195 
launchShortcutTargetActivity(int displayId, ComponentName name)196     private void launchShortcutTargetActivity(int displayId, ComponentName name) {
197         final Intent intent = new Intent();
198         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
199 
200         intent.setComponent(name);
201         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
202         try {
203             final int userId = UserHandle.myUserId();
204             getPrefContext().startActivityAsUser(intent, bundle, UserHandle.of(userId));
205         } catch (ActivityNotFoundException ignore) {
206             // ignore the exception
207             Log.w(TAG, "Target activity not found.");
208         }
209     }
210 
211     @Nullable
getSettingsIntent(Bundle arguments)212     private Intent getSettingsIntent(Bundle arguments) {
213         final String settingsComponentName = arguments.getString(
214                 AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
215         if (TextUtils.isEmpty(settingsComponentName)) {
216             return null;
217         }
218 
219         final Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
220                 ComponentName.unflattenFromString(settingsComponentName));
221         if (getPackageManager().queryIntentActivities(settingsIntent, /* flags= */ 0).isEmpty()) {
222             return null;
223         }
224 
225         return settingsIntent;
226     }
227 
228     @Override
getPreferenceScreenResId()229     protected int getPreferenceScreenResId() {
230         // TODO(b/171272809): Add back when controllers move to static type
231         return 0;
232     }
233 
234     @Override
getLogTag()235     protected String getLogTag() {
236         return TAG;
237     }
238 }
239