1 /* 2 * Copyright (C) 2017 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 package com.android.internal.app; 17 18 import android.accessibilityservice.AccessibilityServiceInfo; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.Activity; 22 import android.content.Context; 23 import android.graphics.drawable.Drawable; 24 import android.os.Bundle; 25 import android.provider.Settings; 26 import android.text.TextUtils; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.accessibility.AccessibilityManager; 31 import android.widget.BaseAdapter; 32 import android.widget.GridView; 33 import android.widget.ImageView; 34 import android.widget.TextView; 35 36 import com.android.internal.R; 37 import com.android.internal.widget.ResolverDrawerLayout; 38 39 import java.util.ArrayList; 40 import java.util.Collections; 41 import java.util.List; 42 43 /** 44 * Activity used to display and persist a service or feature target for the Accessibility button. 45 */ 46 public class AccessibilityButtonChooserActivity extends Activity { 47 48 private static final String MAGNIFICATION_COMPONENT_ID = 49 "com.android.server.accessibility.MagnificationController"; 50 51 private AccessibilityButtonTarget mMagnificationTarget = null; 52 53 private List<AccessibilityButtonTarget> mTargets = null; 54 55 @Override onCreate(@ullable Bundle savedInstanceState)56 protected void onCreate(@Nullable Bundle savedInstanceState) { 57 super.onCreate(savedInstanceState); 58 setContentView(R.layout.accessibility_button_chooser); 59 60 final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); 61 if (rdl != null) { 62 rdl.setOnDismissedListener(this::finish); 63 } 64 65 String component = Settings.Secure.getString(getContentResolver(), 66 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); 67 if (TextUtils.isEmpty(component)) { 68 TextView prompt = findViewById(R.id.accessibility_button_prompt); 69 prompt.setVisibility(View.VISIBLE); 70 } 71 72 mMagnificationTarget = new AccessibilityButtonTarget(this, MAGNIFICATION_COMPONENT_ID, 73 R.string.accessibility_magnification_chooser_text, 74 R.drawable.ic_accessibility_magnification); 75 76 mTargets = getServiceAccessibilityButtonTargets(this); 77 if (Settings.Secure.getInt(getContentResolver(), 78 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1) { 79 mTargets.add(mMagnificationTarget); 80 } 81 82 if (mTargets.size() < 2) { 83 // Why are we here? 84 finish(); 85 } 86 87 GridView gridview = findViewById(R.id.accessibility_button_chooser_grid); 88 gridview.setAdapter(new TargetAdapter()); 89 gridview.setOnItemClickListener((parent, view, position, id) -> { 90 onTargetSelected(mTargets.get(position)); 91 }); 92 } 93 getServiceAccessibilityButtonTargets( @onNull Context context)94 private static List<AccessibilityButtonTarget> getServiceAccessibilityButtonTargets( 95 @NonNull Context context) { 96 AccessibilityManager ams = (AccessibilityManager) context.getSystemService( 97 Context.ACCESSIBILITY_SERVICE); 98 List<AccessibilityServiceInfo> services = ams.getEnabledAccessibilityServiceList( 99 AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 100 if (services == null) { 101 return Collections.emptyList(); 102 } 103 104 ArrayList<AccessibilityButtonTarget> targets = new ArrayList<>(services.size()); 105 for (AccessibilityServiceInfo info : services) { 106 if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) { 107 targets.add(new AccessibilityButtonTarget(context, info)); 108 } 109 } 110 111 return targets; 112 } 113 onTargetSelected(AccessibilityButtonTarget target)114 private void onTargetSelected(AccessibilityButtonTarget target) { 115 Settings.Secure.putString(getContentResolver(), 116 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, target.getId()); 117 finish(); 118 } 119 120 private class TargetAdapter extends BaseAdapter { 121 @Override getCount()122 public int getCount() { 123 return mTargets.size(); 124 } 125 126 @Override getItem(int position)127 public Object getItem(int position) { 128 return null; 129 } 130 131 @Override getItemId(int position)132 public long getItemId(int position) { 133 return position; 134 } 135 136 @Override getView(int position, View convertView, ViewGroup parent)137 public View getView(int position, View convertView, ViewGroup parent) { 138 LayoutInflater inflater = AccessibilityButtonChooserActivity.this.getLayoutInflater(); 139 View root = inflater.inflate(R.layout.accessibility_button_chooser_item, parent, false); 140 final AccessibilityButtonTarget target = mTargets.get(position); 141 ImageView iconView = root.findViewById(R.id.accessibility_button_target_icon); 142 TextView labelView = root.findViewById(R.id.accessibility_button_target_label); 143 iconView.setImageDrawable(target.getDrawable()); 144 labelView.setText(target.getLabel()); 145 return root; 146 } 147 } 148 149 private static class AccessibilityButtonTarget { 150 public String mId; 151 public CharSequence mLabel; 152 public Drawable mDrawable; 153 AccessibilityButtonTarget(@onNull Context context, @NonNull AccessibilityServiceInfo serviceInfo)154 public AccessibilityButtonTarget(@NonNull Context context, 155 @NonNull AccessibilityServiceInfo serviceInfo) { 156 this.mId = serviceInfo.getComponentName().flattenToString(); 157 this.mLabel = serviceInfo.getResolveInfo().loadLabel(context.getPackageManager()); 158 this.mDrawable = serviceInfo.getResolveInfo().loadIcon(context.getPackageManager()); 159 } 160 AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId, int iconRes)161 public AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId, 162 int iconRes) { 163 this.mId = id; 164 this.mLabel = context.getText(labelResId); 165 this.mDrawable = context.getDrawable(iconRes); 166 } 167 getId()168 public String getId() { 169 return mId; 170 } 171 getLabel()172 public CharSequence getLabel() { 173 return mLabel; 174 } 175 getDrawable()176 public Drawable getDrawable() { 177 return mDrawable; 178 } 179 } 180 }