blob: dcf1f1cbf85f9883ed365df6debd0b2d9128043e [file] [log] [blame]
/*
* Copyright (C) 2017 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.settings.accessibility;
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityManager;
import android.view.View;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.accessibility.AccessibilityUtils;
import com.android.settingslib.widget.CandidateInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Fragment for picking accessibility shortcut service
*/
public class ShortcutServicePickerFragment extends RadioButtonPickerFragment {
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_shortcut_service_settings;
}
@Override
protected List<? extends CandidateInfo> getCandidates() {
final Context context = getContext();
final AccessibilityManager accessibilityManager = context
.getSystemService(AccessibilityManager.class);
final List<AccessibilityServiceInfo> installedServices =
accessibilityManager.getInstalledAccessibilityServiceList();
final int numInstalledServices = installedServices.size();
final List<CandidateInfo> candidates = new ArrayList<>(numInstalledServices);
Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureInfoMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
for (ComponentName componentName : frameworkFeatureInfoMap.keySet()) {
final int iconId;
if (componentName.equals(COLOR_INVERSION_COMPONENT_NAME)) {
iconId = R.drawable.ic_color_inversion;
} else if (componentName.equals(DALTONIZER_COMPONENT_NAME)) {
iconId = R.drawable.ic_daltonizer;
} else {
iconId = R.drawable.empty_icon;
}
candidates.add(new FrameworkCandidateInfo(frameworkFeatureInfoMap.get(componentName),
iconId, componentName.flattenToString()));
}
for (int i = 0; i < numInstalledServices; i++) {
candidates.add(new ServiceCandidateInfo(installedServices.get(i)));
}
return candidates;
}
@Override
protected String getDefaultKey() {
String shortcutServiceString = AccessibilityUtils
.getShortcutTargetServiceComponentNameString(getContext(), UserHandle.myUserId());
if (shortcutServiceString != null) {
ComponentName shortcutName = ComponentName.unflattenFromString(shortcutServiceString);
if (shortcutName != null) {
return shortcutName.flattenToString();
}
}
return null;
}
@Override
protected boolean setDefaultKey(String key) {
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, key);
return true;
}
@Override
public void onRadioButtonClicked(RadioButtonPreference selected) {
final String selectedKey = selected.getKey();
if (TextUtils.isEmpty(selectedKey)) {
super.onRadioButtonClicked(selected);
} else {
final ComponentName selectedComponent = ComponentName.unflattenFromString(selectedKey);
if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
.containsKey(selectedComponent)) {
// This is a framework feature. It doesn't need to be confirmed.
onRadioButtonConfirmed(selectedKey);
} else {
final FragmentActivity activity = getActivity();
if (activity != null) {
ConfirmationDialogFragment.newInstance(this, selectedKey)
.show(activity.getSupportFragmentManager(),
ConfirmationDialogFragment.TAG);
}
}
}
}
private void onServiceConfirmed(String serviceKey) {
onRadioButtonConfirmed(serviceKey);
}
public static class ConfirmationDialogFragment extends InstrumentedDialogFragment
implements View.OnClickListener {
private static final String EXTRA_KEY = "extra_key";
private static final String TAG = "ConfirmationDialogFragment";
private IBinder mToken;
public static ConfirmationDialogFragment newInstance(ShortcutServicePickerFragment parent,
String key) {
final ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();
final Bundle argument = new Bundle();
argument.putString(EXTRA_KEY, key);
fragment.setArguments(argument);
fragment.setTargetFragment(parent, 0);
fragment.mToken = new Binder();
return fragment;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle bundle = getArguments();
final String key = bundle.getString(EXTRA_KEY);
final ComponentName serviceComponentName = ComponentName.unflattenFromString(key);
final AccessibilityManager accessibilityManager = getActivity()
.getSystemService(AccessibilityManager.class);
AccessibilityServiceInfo info = accessibilityManager
.getInstalledServiceInfoWithComponentName(serviceComponentName);
return AccessibilityServiceWarning.createCapabilitiesDialog(getActivity(), info, this);
}
@Override
public void onClick(View view) {
final Fragment fragment = getTargetFragment();
if ((view.getId() == R.id.permission_enable_allow_button)
&& (fragment instanceof ShortcutServicePickerFragment)) {
final Bundle bundle = getArguments();
((ShortcutServicePickerFragment) fragment).onServiceConfirmed(
bundle.getString(EXTRA_KEY));
}
dismiss();
}
}
private class FrameworkCandidateInfo extends CandidateInfo {
final ToggleableFrameworkFeatureInfo mToggleableFrameworkFeatureInfo;
final int mIconResId;
final String mKey;
public FrameworkCandidateInfo(
ToggleableFrameworkFeatureInfo frameworkFeatureInfo, int iconResId, String key) {
super(true /* enabled */);
mToggleableFrameworkFeatureInfo = frameworkFeatureInfo;
mIconResId = iconResId;
mKey = key;
}
@Override
public CharSequence loadLabel() {
return mToggleableFrameworkFeatureInfo.getLabel(getContext());
}
@Override
public Drawable loadIcon() {
return getContext().getDrawable(mIconResId);
}
@Override
public String getKey() {
return mKey;
}
}
private class ServiceCandidateInfo extends CandidateInfo {
final AccessibilityServiceInfo mServiceInfo;
public ServiceCandidateInfo(AccessibilityServiceInfo serviceInfo) {
super(true /* enabled */);
mServiceInfo = serviceInfo;
}
@Override
public CharSequence loadLabel() {
final PackageManager pmw = getContext().getPackageManager();
final CharSequence label =
mServiceInfo.getResolveInfo().serviceInfo.loadLabel(pmw);
if (label != null) {
return label;
}
final ComponentName componentName = mServiceInfo.getComponentName();
if (componentName != null) {
try {
final ApplicationInfo appInfo = pmw.getApplicationInfoAsUser(
componentName.getPackageName(), 0, UserHandle.myUserId());
return appInfo.loadLabel(pmw);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
return null;
}
@Override
public Drawable loadIcon() {
final ResolveInfo resolveInfo = mServiceInfo.getResolveInfo();
return (resolveInfo.getIconResource() == 0)
? getContext().getDrawable(R.drawable.ic_accessibility_generic)
: resolveInfo.loadIcon(getContext().getPackageManager());
}
@Override
public String getKey() {
return mServiceInfo.getComponentName().flattenToString();
}
}
}