diff options
14 files changed, 702 insertions, 0 deletions
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java new file mode 100644 index 000000000000..4c7d93b7446a --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey; +import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType; +import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained; + +import android.accessibilityservice.AccessibilityShortcutInfo; +import android.annotation.NonNull; +import android.content.Context; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; + +/** + * Base class for creating accessibility activity target. + */ +class AccessibilityActivityTarget extends AccessibilityTarget { + + AccessibilityActivityTarget(Context context, @ShortcutType int shortcutType, + @NonNull AccessibilityShortcutInfo shortcutInfo) { + super(context, + shortcutType, + AccessibilityFragmentType.LAUNCH_ACTIVITY, + isShortcutContained(context, shortcutType, + shortcutInfo.getComponentName().flattenToString()), + shortcutInfo.getComponentName().flattenToString(), + shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager()), + shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager()), + convertToKey(convertToUserType(shortcutType))); + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java new file mode 100644 index 000000000000..e64f78a3f207 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey; +import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType; +import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.NonNull; +import android.content.Context; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; + +/** + * Base class for creating accessibility service target with various fragment types related to + * legacy type, invisible type and intuitive type. + */ +class AccessibilityServiceTarget extends AccessibilityTarget { + + AccessibilityServiceTarget(Context context, @ShortcutType int shortcutType, + @AccessibilityFragmentType int fragmentType, + @NonNull AccessibilityServiceInfo serviceInfo) { + super(context, + shortcutType, + fragmentType, + isShortcutContained(context, shortcutType, + serviceInfo.getComponentName().flattenToString()), + serviceInfo.getComponentName().flattenToString(), + serviceInfo.getResolveInfo().loadLabel(context.getPackageManager()), + serviceInfo.getResolveInfo().loadIcon(context.getPackageManager()), + convertToKey(convertToUserType(shortcutType))); + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java new file mode 100644 index 000000000000..72ebc58380b8 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; + +import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType; +import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings; +import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings; + +import android.annotation.NonNull; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; +import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; + +/** + * Abstract base class for creating various target related to accessibility service, + * accessibility activity, and white listing feature. + */ +abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener, + OnTargetCheckedChangeListener { + private Context mContext; + @ShortcutType + private int mShortcutType; + @AccessibilityFragmentType + private int mFragmentType; + private boolean mShortcutEnabled; + private String mId; + private CharSequence mLabel; + private Drawable mIcon; + private String mKey; + + AccessibilityTarget(Context context, @ShortcutType int shortcutType, + @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, + CharSequence label, Drawable icon, String key) { + mContext = context; + mShortcutType = shortcutType; + mFragmentType = fragmentType; + mShortcutEnabled = isShortcutSwitched; + mId = id; + mLabel = label; + mIcon = icon; + mKey = key; + } + + @Override + public void updateActionItem(@NonNull ViewHolder holder, + @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode) { + final boolean isEditMenuMode = + shortcutMenuMode == ShortcutConstants.ShortcutMenuMode.EDIT; + + holder.mCheckBoxView.setChecked(isEditMenuMode && isShortcutEnabled()); + holder.mCheckBoxView.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE); + holder.mIconView.setImageDrawable(getIcon()); + holder.mLabelView.setText(getLabel()); + holder.mSwitchItem.setVisibility(View.GONE); + } + + @Override + public void onSelected() { + final AccessibilityManager am = + getContext().getSystemService(AccessibilityManager.class); + switch (getShortcutType()) { + case ACCESSIBILITY_BUTTON: + am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId()); + return; + case ACCESSIBILITY_SHORTCUT_KEY: + am.performAccessibilityShortcut(getId()); + return; + default: + throw new IllegalStateException("Unexpected shortcut type"); + } + } + + @Override + public void onCheckedChanged(boolean isChecked) { + setShortcutEnabled(isChecked); + if (isChecked) { + optInValueToSettings(getContext(), convertToUserType(getShortcutType()), getId()); + } else { + optOutValueFromSettings(getContext(), convertToUserType(getShortcutType()), getId()); + } + } + + public void setShortcutEnabled(boolean enabled) { + mShortcutEnabled = enabled; + } + + public Context getContext() { + return mContext; + } + + public @ShortcutType int getShortcutType() { + return mShortcutType; + } + + public @AccessibilityFragmentType int getFragmentType() { + return mFragmentType; + } + + public boolean isShortcutEnabled() { + return mShortcutEnabled; + } + + public String getId() { + return mId; + } + + public CharSequence getLabel() { + return mLabel; + } + + public Drawable getIcon() { + return mIcon; + } + + public String getKey() { + return mKey; + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java new file mode 100644 index 000000000000..9d5c374e98f5 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; + +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; +import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState; +import static com.android.internal.accessibility.util.ShortcutUtils.isComponentIdExistingInSettings; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; + +/** + * Extension for {@link AccessibilityServiceTarget} with + * {@link AccessibilityFragmentType#INVISIBLE_TOGGLE} type. + */ +class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarget { + + InvisibleToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType, + @NonNull AccessibilityServiceInfo serviceInfo) { + super(context, + shortcutType, + AccessibilityFragmentType.INVISIBLE_TOGGLE, + serviceInfo); + } + + @Override + public void onCheckedChanged(boolean isChecked) { + final ComponentName componentName = ComponentName.unflattenFromString(getId()); + + if (!isComponentIdExistingInOtherShortcut()) { + setAccessibilityServiceState(getContext(), componentName, isChecked); + } + + super.onCheckedChanged(isChecked); + } + + private boolean isComponentIdExistingInOtherShortcut() { + switch (getShortcutType()) { + case ACCESSIBILITY_BUTTON: + return isComponentIdExistingInSettings(getContext(), UserShortcutType.HARDWARE, + getId()); + case ACCESSIBILITY_SHORTCUT_KEY: + return isComponentIdExistingInSettings(getContext(), UserShortcutType.SOFTWARE, + getId()); + default: + throw new IllegalStateException("Unexpected shortcut type"); + } + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java new file mode 100644 index 000000000000..acd101bf28ba --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; + +/** + * Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#INVISIBLE_TOGGLE} + * type. + */ +class InvisibleToggleWhiteListingFeatureTarget extends AccessibilityTarget { + + InvisibleToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType, + boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) { + super(context, shortcutType, AccessibilityFragmentType.INVISIBLE_TOGGLE, + isShortcutSwitched, id, label, icon, key); + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/OnTargetCheckedChangeListener.java b/core/java/com/android/internal/accessibility/dialog/OnTargetCheckedChangeListener.java new file mode 100644 index 000000000000..dab45e45907d --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/OnTargetCheckedChangeListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +/** + * Interface definition for a callback to be invoked when the checked state + * of a accessibility target changed. + */ +interface OnTargetCheckedChangeListener { + /** + * Called when the checked state of a accessibility target has changed. + * + * @param isChecked The new checked state of accessibility target. + */ + void onCheckedChanged(boolean isChecked); +} diff --git a/core/java/com/android/internal/accessibility/dialog/OnTargetSelectedListener.java b/core/java/com/android/internal/accessibility/dialog/OnTargetSelectedListener.java new file mode 100644 index 000000000000..b3e976f296a9 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/OnTargetSelectedListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +/** + * Interface definition for a callback to be invoked when a accessibility target is selected. + */ +interface OnTargetSelectedListener { + /** + * Called when a accessibility target has been selected. + */ + void onSelected(); +} diff --git a/core/java/com/android/internal/accessibility/dialog/TargetAdapter.java b/core/java/com/android/internal/accessibility/dialog/TargetAdapter.java new file mode 100644 index 000000000000..1efa17e520ae --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/TargetAdapter.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import android.widget.BaseAdapter; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.Switch; +import android.widget.TextView; + +/** + * Abstract base class for creating target adapter for chooser activity. + */ +abstract class TargetAdapter extends BaseAdapter { + static class ViewHolder{ + CheckBox mCheckBoxView; + ImageView mIconView; + TextView mLabelView; + Switch mSwitchItem; + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/TargetOperations.java b/core/java/com/android/internal/accessibility/dialog/TargetOperations.java new file mode 100644 index 000000000000..77cc5b454ed7 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/TargetOperations.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import android.annotation.NonNull; + +import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; +import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; + +/** + * Interface definition for operations with a accessibility target that was invoked. + */ +interface TargetOperations { + /** + * Called when a accessibility target has been invoked and notified to update latest status. + */ + void updateActionItem(@NonNull ViewHolder holder, + @ShortcutMenuMode int shortcutMenuMode); +} diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java new file mode 100644 index 000000000000..3a42f7e0edb8 --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static com.android.internal.accessibility.util.AccessibilityUtils.isAccessibilityServiceEnabled; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.NonNull; +import android.content.Context; +import android.view.View; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; +import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; +import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; + +/** + * Extension for {@link AccessibilityServiceTarget} with {@link AccessibilityFragmentType#TOGGLE} + * type. + */ +class ToggleAccessibilityServiceTarget extends AccessibilityServiceTarget { + + ToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType, + @NonNull AccessibilityServiceInfo serviceInfo) { + super(context, + shortcutType, + AccessibilityFragmentType.TOGGLE, + serviceInfo); + } + + @Override + public void updateActionItem(@NonNull ViewHolder holder, + @ShortcutMenuMode int shortcutMenuMode) { + super.updateActionItem(holder, shortcutMenuMode); + + final boolean isEditMenuMode = + shortcutMenuMode == ShortcutMenuMode.EDIT; + holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE); + holder.mSwitchItem.setChecked(isAccessibilityServiceEnabled(getContext(), getId())); + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java new file mode 100644 index 000000000000..fcbf5eccbd9e --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import android.annotation.NonNull; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.provider.Settings; +import android.view.View; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; +import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; +import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; + +/** + * Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#TOGGLE} + * type. + */ +class ToggleWhiteListingFeatureTarget extends AccessibilityTarget { + + ToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType, + boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) { + super(context, shortcutType, AccessibilityFragmentType.TOGGLE, + isShortcutSwitched, id, label, icon, key); + } + + @Override + public void updateActionItem(@NonNull ViewHolder holder, + @ShortcutMenuMode int shortcutMenuMode) { + super.updateActionItem(holder, shortcutMenuMode); + + final boolean isEditMenuMode = + shortcutMenuMode == ShortcutMenuMode.EDIT; + holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE); + holder.mSwitchItem.setChecked(isFeatureEnabled()); + } + + private boolean isFeatureEnabled() { + return Settings.Secure.getInt(getContext().getContentResolver(), + getKey(), /* settingsValueOff */ 0) == /* settingsValueOn */ 1; + } +} diff --git a/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java new file mode 100644 index 000000000000..04f5061fbd8e --- /dev/null +++ b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.dialog; + +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; + +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; +import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState; +import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.view.accessibility.AccessibilityManager.ShortcutType; +import android.widget.Toast; + +import com.android.internal.R; +import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; + +/** + * Extension for {@link AccessibilityServiceTarget} with + * {@link AccessibilityFragmentType#VOLUME_SHORTCUT_TOGGLE} type. + */ +class VolumeShortcutToggleAccessibilityServiceTarget extends AccessibilityServiceTarget { + + VolumeShortcutToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType, + @NonNull AccessibilityServiceInfo serviceInfo) { + super(context, + shortcutType, + AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE, + serviceInfo); + } + + @Override + public void onCheckedChanged(boolean isChecked) { + switch (getShortcutType()) { + case ACCESSIBILITY_BUTTON: + onCheckedFromAccessibilityButton(isChecked); + return; + case ACCESSIBILITY_SHORTCUT_KEY: + super.onCheckedChanged(isChecked); + return; + default: + throw new IllegalStateException("Unexpected shortcut type"); + } + } + + private void onCheckedFromAccessibilityButton(boolean isChecked) { + setShortcutEnabled(isChecked); + final ComponentName componentName = ComponentName.unflattenFromString(getId()); + setAccessibilityServiceState(getContext(), componentName, isChecked); + + if (!isChecked) { + optOutValueFromSettings(getContext(), UserShortcutType.HARDWARE, getId()); + + final String warningText = + getContext().getString(R.string.accessibility_uncheck_legacy_item_warning, + getLabel()); + Toast.makeText(getContext(), warningText, Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java index a92a50d4d832..e50b010d691a 100644 --- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java +++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java @@ -15,6 +15,7 @@ */ package com.android.internal.accessibility.util; + import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; @@ -27,9 +28,11 @@ import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; +import android.view.accessibility.AccessibilityManager; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -129,4 +132,27 @@ public final class AccessibilityUtils { ? AccessibilityFragmentType.INVISIBLE_TOGGLE : AccessibilityFragmentType.TOGGLE; } + + /** + * Returns if a {@code componentId} service is enabled. + * + * @param context The current context. + * @param componentId The component id that need to be checked. + * @return {@code true} if a {@code componentId} service is enabled. + */ + public static boolean isAccessibilityServiceEnabled(Context context, + @NonNull String componentId) { + final AccessibilityManager am = context.getSystemService(AccessibilityManager.class); + final List<AccessibilityServiceInfo> enabledServices = + am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); + + for (AccessibilityServiceInfo info : enabledServices) { + final String id = info.getComponentName().flattenToString(); + if (id.equals(componentId)) { + return true; + } + } + + return false; + } } diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java index 7ec80ecdb2a9..fa90b49e85af 100644 --- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -25,8 +25,10 @@ import android.annotation.NonNull; import android.content.Context; import android.provider.Settings; import android.text.TextUtils; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.ShortcutType; +import java.util.List; import java.util.StringJoiner; /** @@ -149,6 +151,21 @@ public final class ShortcutUtils { } /** + * Returns if a {@code shortcutType} shortcut contains {@code componentId}. + * + * @param context The current context. + * @param shortcutType The preferred shortcut type user selected. + * @param componentId The component id that need to be checked. + * @return {@code true} if a component id is contained. + */ + public static boolean isShortcutContained(Context context, @ShortcutType int shortcutType, + @NonNull String componentId) { + final AccessibilityManager am = context.getSystemService(AccessibilityManager.class); + final List<String> requiredTargets = am.getAccessibilityShortcutTargets(shortcutType); + return requiredTargets.contains(componentId); + } + + /** * Converts {@link UserShortcutType} to {@link Settings.Secure} key. * * @param type The shortcut type. |