Merge changes from topic "tutorial_improvement" into rvc-dev am: b6bf10ebbc am: 15d20efe43

Change-Id: I428a0bbc42ebd562e9ade929160114735ca13995
This commit is contained in:
PETER LIANG
2020-04-23 13:00:12 +00:00
committed by Automerger Merge Worker
14 changed files with 588 additions and 27 deletions

View File

@@ -15,8 +15,8 @@
--> -->
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="18dp"
android:height="24dp" android:height="18dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">

View File

@@ -0,0 +1,26 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal">
<path
android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,58 @@
<!--
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.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textDirection="locale"
android:scrollbarStyle="outsideOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextSwitcher
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:measureAllChildren="false" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="176dp"
android:paddingTop="16dp"
android:paddingBottom="16dp" />
<LinearLayout
android:id="@+id/indicator_container"
android:layout_width="wrap_content"
android:layout_height="10dp"
android:layout_gravity="center" />
<TextSwitcher
android:id="@+id/instruction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:measureAllChildren="false" />
</LinearLayout>
</ScrollView>

View File

@@ -16,35 +16,55 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.style.ImageSpan; import android.text.style.ImageSpan;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.TextureView; import android.view.TextureView;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextSwitcher;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.AnimRes;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.util.Preconditions;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/** /**
* Utility class for creating the dialog that guides users for gesture navigation for * Utility class for creating the dialog that guides users for gesture navigation for
* accessibility services. * accessibility services.
*/ */
public class AccessibilityGestureNavigationTutorial { public final class AccessibilityGestureNavigationTutorial {
/** IntDef enum for dialog type. */ /** IntDef enum for dialog type. */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({ @IntDef({
@@ -59,6 +79,8 @@ public class AccessibilityGestureNavigationTutorial {
int GESTURE_NAVIGATION_SETTINGS = 2; int GESTURE_NAVIGATION_SETTINGS = 2;
} }
private AccessibilityGestureNavigationTutorial() {}
private static final DialogInterface.OnClickListener mOnClickListener = private static final DialogInterface.OnClickListener mOnClickListener =
(DialogInterface dialog, int which) -> dialog.dismiss(); (DialogInterface dialog, int which) -> dialog.dismiss();
@@ -91,6 +113,13 @@ public class AccessibilityGestureNavigationTutorial {
return createDialog(context, DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION); return createDialog(context, DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION);
} }
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes) {
return new AlertDialog.Builder(context)
.setView(createShortcutNavigationContentView(context, shortcutTypes))
.setNegativeButton(R.string.accessibility_tutorial_dialog_button, mOnClickListener)
.create();
}
/** /**
* Get a content View for a dialog to confirm that they want to enable a service. * Get a content View for a dialog to confirm that they want to enable a service.
* *
@@ -201,4 +230,302 @@ public class AccessibilityGestureNavigationTutorial {
typedArray.recycle(); typedArray.recycle();
return colorResId; return colorResId;
} }
private static class TutorialPagerAdapter extends PagerAdapter {
private final List<TutorialPage> mTutorialPages;
private TutorialPagerAdapter(List<TutorialPage> tutorialPages) {
this.mTutorialPages = tutorialPages;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
final View itemView = mTutorialPages.get(position).getImageView();
container.addView(itemView);
return itemView;
}
@Override
public int getCount() {
return mTutorialPages.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == o;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position,
@NonNull Object object) {
final View itemView = mTutorialPages.get(position).getImageView();
container.removeView(itemView);
}
}
private static ImageView createImageView(Context context, int imageRes) {
final ImageView imageView = new ImageView(context);
imageView.setImageResource(imageRes);
imageView.setAdjustViewBounds(true);
return imageView;
}
private static View createShortcutNavigationContentView(Context context, int shortcutTypes) {
final LayoutInflater inflater = context.getSystemService(LayoutInflater.class);
final View contentView = inflater.inflate(
R.layout.accessibility_shortcut_tutorial_dialog, /* root= */ null);
final List<TutorialPage> tutorialPages =
createShortcutTutorialPages(context, shortcutTypes);
Preconditions.checkArgument(!tutorialPages.isEmpty(),
/* errorMessage= */ "Unexpected tutorial pages size");
final LinearLayout indicatorContainer = contentView.findViewById(R.id.indicator_container);
indicatorContainer.setVisibility(tutorialPages.size() > 1 ? VISIBLE : GONE);
for (TutorialPage page : tutorialPages) {
indicatorContainer.addView(page.getIndicatorIcon());
}
tutorialPages.get(/* firstIndex */ 0).getIndicatorIcon().setEnabled(true);
final TextSwitcher title = contentView.findViewById(R.id.title);
title.setFactory(() -> makeTitleView(context));
title.setText(tutorialPages.get(/* firstIndex */ 0).getTitle());
final TextSwitcher instruction = contentView.findViewById(R.id.instruction);
instruction.setFactory(() -> makeInstructionView(context));
instruction.setText(tutorialPages.get(/* firstIndex */ 0).getInstruction());
final ViewPager viewPager = contentView.findViewById(R.id.view_pager);
viewPager.setAdapter(new TutorialPagerAdapter(tutorialPages));
viewPager.addOnPageChangeListener(
new TutorialPageChangeListener(context, title, instruction, tutorialPages));
return contentView;
}
private static View makeTitleView(Context context) {
final String familyName =
context.getString(
com.android.internal.R.string.config_headlineFontFamilyMedium);
final TextView textView = new TextView(context);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, /* size= */ 20);
textView.setTextColor(Utils.getColorAttr(context, android.R.attr.textColorPrimary));
textView.setGravity(Gravity.CENTER);
textView.setTypeface(Typeface.create(familyName, Typeface.NORMAL));
return textView;
}
private static View makeInstructionView(Context context) {
final TextView textView = new TextView(context);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, /* size= */ 16);
textView.setTextColor(Utils.getColorAttr(context, android.R.attr.textColorPrimary));
textView.setTypeface(
Typeface.create(/* familyName= */ "sans-serif", Typeface.NORMAL));
return textView;
}
private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) {
final CharSequence title = getSoftwareTitle(context);
final ImageView image = createSoftwareImage(context);
final CharSequence instruction = getSoftwareInstruction(context);
final ImageView indicatorIcon =
createImageView(context, R.drawable.ic_accessibility_page_indicator);
indicatorIcon.setEnabled(false);
return new TutorialPage(title, image, indicatorIcon, instruction);
}
private static TutorialPage createHardwareTutorialPage(@NonNull Context context) {
final CharSequence title =
context.getText(R.string.accessibility_tutorial_dialog_title_volume);
final ImageView image =
createImageView(context, R.drawable.accessibility_shortcut_type_hardware);
final ImageView indicatorIcon =
createImageView(context, R.drawable.ic_accessibility_page_indicator);
final CharSequence instruction =
context.getText(R.string.accessibility_tutorial_dialog_message_volume);
indicatorIcon.setEnabled(false);
return new TutorialPage(title, image, indicatorIcon, instruction);
}
private static TutorialPage createTripleTapTutorialPage(@NonNull Context context) {
final CharSequence title =
context.getText(R.string.accessibility_tutorial_dialog_title_triple);
final ImageView image =
createImageView(context, R.drawable.accessibility_shortcut_type_triple_tap);
final CharSequence instruction =
context.getText(R.string.accessibility_tutorial_dialog_message_triple);
final ImageView indicatorIcon =
createImageView(context, R.drawable.ic_accessibility_page_indicator);
indicatorIcon.setEnabled(false);
return new TutorialPage(title, image, indicatorIcon, instruction);
}
@VisibleForTesting
static List<TutorialPage> createShortcutTutorialPages(@NonNull Context context,
int shortcutTypes) {
final List<TutorialPage> tutorialPages = new ArrayList<>();
if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
tutorialPages.add(createSoftwareTutorialPage(context));
}
if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) {
tutorialPages.add(createHardwareTutorialPage(context));
}
if ((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP) {
tutorialPages.add(createTripleTapTutorialPage(context));
}
return tutorialPages;
}
private static CharSequence getSoftwareTitle(Context context) {
final boolean isGestureNavigationEnabled =
AccessibilityUtil.isGestureNavigateEnabled(context);
final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
return (isGestureNavigationEnabled || isTouchExploreEnabled)
? context.getText(R.string.accessibility_tutorial_dialog_title_gesture)
: context.getText(R.string.accessibility_tutorial_dialog_title_button);
}
private static ImageView createSoftwareImage(Context context) {
int resId = R.drawable.accessibility_shortcut_type_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
resId = AccessibilityUtil.isTouchExploreEnabled(context)
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
: R.drawable.accessibility_shortcut_type_software_gesture;
}
return createImageView(context, resId);
}
private static CharSequence getSoftwareInstruction(Context context) {
final boolean isGestureNavigateEnabled =
AccessibilityUtil.isGestureNavigateEnabled(context);
final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
int resId = R.string.accessibility_tutorial_dialog_message_button;
if (isGestureNavigateEnabled) {
resId = isTouchExploreEnabled
? R.string.accessibility_tutorial_dialog_message_gesture_talkback
: R.string.accessibility_tutorial_dialog_message_gesture;
}
CharSequence text = context.getText(resId);
if (resId == R.string.accessibility_tutorial_dialog_message_button) {
text = getSoftwareInstructionWithIcon(context, text);
}
return text;
}
private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {
final String message = text.toString();
final SpannableString spannableInstruction = SpannableString.valueOf(message);
final int indexIconStart = message.indexOf("%s");
final int indexIconEnd = indexIconStart + 2;
final ImageView iconView = new ImageView(context);
iconView.setImageDrawable(context.getDrawable(R.drawable.ic_accessibility_new));
final Drawable icon = iconView.getDrawable().mutate();
final ImageSpan imageSpan = new ImageSpan(icon);
imageSpan.setContentDescription("");
icon.setBounds(/* left= */ 0, /* top= */ 0,
icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
spannableInstruction.setSpan(imageSpan, indexIconStart, indexIconEnd,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableInstruction;
}
private static class TutorialPage {
private final CharSequence mTitle;
private final ImageView mImageView;
private final ImageView mIndicatorIcon;
private final CharSequence mInstruction;
TutorialPage(CharSequence title, ImageView imageView, ImageView indicatorIcon,
CharSequence instruction) {
this.mTitle = title;
this.mImageView = imageView;
this.mIndicatorIcon = indicatorIcon;
this.mInstruction = instruction;
}
public CharSequence getTitle() {
return mTitle;
}
public ImageView getImageView() {
return mImageView;
}
public ImageView getIndicatorIcon() {
return mIndicatorIcon;
}
public CharSequence getInstruction() {
return mInstruction;
}
}
private static class TutorialPageChangeListener implements ViewPager.OnPageChangeListener {
private int mLastTutorialPagePosition = 0;
private final Context mContext;
private final TextSwitcher mTitle;
private final TextSwitcher mInstruction;
private final List<TutorialPage> mTutorialPages;
TutorialPageChangeListener(Context context, ViewGroup title, ViewGroup instruction,
List<TutorialPage> tutorialPages) {
this.mContext = context;
this.mTitle = (TextSwitcher) title;
this.mInstruction = (TextSwitcher) instruction;
this.mTutorialPages = tutorialPages;
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// Do nothing.
}
@Override
public void onPageSelected(int position) {
final boolean isPreviousPosition =
mLastTutorialPagePosition > position;
@AnimRes
final int inAnimationResId = isPreviousPosition
? android.R.anim.slide_in_left
: com.android.internal.R.anim.slide_in_right;
@AnimRes
final int outAnimationResId = isPreviousPosition
? android.R.anim.slide_out_right
: com.android.internal.R.anim.slide_out_left;
mTitle.setInAnimation(mContext, inAnimationResId);
mTitle.setOutAnimation(mContext, outAnimationResId);
mTitle.setText(mTutorialPages.get(position).getTitle());
mInstruction.setInAnimation(mContext, inAnimationResId);
mInstruction.setOutAnimation(mContext, outAnimationResId);
mInstruction.setText(mTutorialPages.get(position).getInstruction());
for (TutorialPage page : mTutorialPages) {
page.getIndicatorIcon().setEnabled(false);
}
mTutorialPages.get(position).getIndicatorIcon().setEnabled(true);
mLastTutorialPagePosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
// Do nothing.
}
}
} }

View File

@@ -100,6 +100,12 @@ public class LaunchAccessibilityActivityPreferenceFragment extends
showDialog(DialogEnums.EDIT_SHORTCUT); showDialog(DialogEnums.EDIT_SHORTCUT);
} }
@Override
int getUserShortcutTypes() {
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
mComponentName);
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Do not call super. We don't want to see the "Help & feedback" option on this page so as // Do not call super. We don't want to see the "Help & feedback" option on this page so as

View File

@@ -18,6 +18,7 @@ package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
@@ -48,6 +49,22 @@ public class LegacyAccessibilityServicePreferenceFragment extends
setAllowedPreferredShortcutType(UserShortcutType.HARDWARE); setAllowedPreferredShortcutType(UserShortcutType.HARDWARE);
} }
@Override
int getUserShortcutTypes() {
int shortcutTypes = super.getUserShortcutTypes();
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
final boolean hasRequestAccessibilityButtonFlag =
(info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
if (hasRequestAccessibilityButtonFlag) {
shortcutTypes |= UserShortcutType.SOFTWARE;
} else {
shortcutTypes &= (~UserShortcutType.SOFTWARE);
}
return shortcutTypes;
}
private void setAllowedPreferredShortcutType(int type) { private void setAllowedPreferredShortcutType(int type) {
final AccessibilityUserShortcutType shortcut = new AccessibilityUserShortcutType( final AccessibilityUserShortcutType shortcut = new AccessibilityUserShortcutType(
mComponentName.flattenToString(), type); mComponentName.flattenToString(), type);

View File

@@ -106,7 +106,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
// capabilities. For // capabilities. For
// example, before JellyBean MR2 the user was granting the explore by touch // example, before JellyBean MR2 the user was granting the explore by touch
// one. // one.
private AccessibilityServiceInfo getAccessibilityServiceInfo() { AccessibilityServiceInfo getAccessibilityServiceInfo() {
final List<AccessibilityServiceInfo> infos = AccessibilityManager.getInstance( final List<AccessibilityServiceInfo> infos = AccessibilityManager.getInstance(
getPrefContext()).getInstalledAccessibilityServiceList(); getPrefContext()).getInstalledAccessibilityServiceList();
@@ -164,16 +164,6 @@ public class ToggleAccessibilityServicePreferenceFragment extends
this::onDialogButtonFromDisableToggleClicked); this::onDialogButtonFromDisableToggleClicked);
break; break;
} }
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL: {
if (AccessibilityUtil.isGestureNavigateEnabled(getPrefContext())) {
mDialog = AccessibilityGestureNavigationTutorial
.showGestureNavigationTutorialDialog(getPrefContext());
} else {
mDialog = AccessibilityGestureNavigationTutorial
.showAccessibilityButtonTutorialDialog(getPrefContext());
}
break;
}
default: { default: {
mDialog = super.onCreateDialog(dialogId); mDialog = super.onCreateDialog(dialogId);
} }
@@ -197,6 +187,12 @@ public class ToggleAccessibilityServicePreferenceFragment extends
} }
} }
@Override
int getUserShortcutTypes() {
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
mComponentName);
}
@Override @Override
protected void updateToggleServiceTitle(SwitchPreference switchPreference) { protected void updateToggleServiceTitle(SwitchPreference switchPreference) {
final AccessibilityServiceInfo info = getAccessibilityServiceInfo(); final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
@@ -301,6 +297,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
} else { } else {
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
mComponentName); mComponentName);
showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
} }
} else { } else {
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes, AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
@@ -414,6 +411,9 @@ public class ToggleAccessibilityServicePreferenceFragment extends
final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE);
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName);
mIsDialogShown.set(false);
showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
mDialog.dismiss(); mDialog.dismiss();
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));

View File

@@ -124,6 +124,12 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
showDialog(DialogEnums.EDIT_SHORTCUT); showDialog(DialogEnums.EDIT_SHORTCUT);
} }
@Override
int getUserShortcutTypes() {
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
mComponentName);
}
private void updateSwitchBarToggleSwitch() { private void updateSwitchBarToggleSwitch() {
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON; final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
if (mToggleServiceDividerSwitchPreference.isChecked() == checked) { if (mToggleServiceDividerSwitchPreference.isChecked() == checked) {

View File

@@ -198,6 +198,12 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
showDialog(DialogEnums.EDIT_SHORTCUT); showDialog(DialogEnums.EDIT_SHORTCUT);
} }
@Override
int getUserShortcutTypes() {
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
mComponentName);
}
private void updateSwitchBarToggleSwitch() { private void updateSwitchBarToggleSwitch() {
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON; final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
if (mToggleServiceDividerSwitchPreference.isChecked() == checked) { if (mToggleServiceDividerSwitchPreference.isChecked() == checked) {

View File

@@ -42,7 +42,6 @@ import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
@@ -250,14 +249,21 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override @Override
public Dialog onCreateDialog(int dialogId) { public Dialog onCreateDialog(int dialogId) {
Dialog dialog;
switch (dialogId) { switch (dialogId) {
case DialogEnums.EDIT_SHORTCUT: case DialogEnums.EDIT_SHORTCUT:
final CharSequence dialogTitle = getPrefContext().getString( final CharSequence dialogTitle = getPrefContext().getString(
R.string.accessibility_shortcut_title, mPackageName); R.string.accessibility_shortcut_title, mPackageName);
final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog( dialog = AccessibilityEditDialogUtils.showEditShortcutDialog(
getPrefContext(), dialogTitle, this::callOnAlertDialogCheckboxClicked); getPrefContext(), dialogTitle, this::callOnAlertDialogCheckboxClicked);
initializeDialogCheckBox(dialog); initializeDialogCheckBox(dialog);
return dialog; return dialog;
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
dialog = AccessibilityGestureNavigationTutorial
.createAccessibilityTutorialDialog(getPrefContext(),
getUserShortcutTypes());
dialog.setCanceledOnTouchOutside(false);
return dialog;
default: default:
throw new IllegalArgumentException("Unsupported dialogId " + dialogId); throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
} }
@@ -268,6 +274,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
switch (dialogId) { switch (dialogId) {
case DialogEnums.EDIT_SHORTCUT: case DialogEnums.EDIT_SHORTCUT:
return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_EDIT_SHORTCUT; return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_EDIT_SHORTCUT;
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
return SettingsEnums.DIALOG_ACCESSIBILITY_TUTORIAL;
default: default:
return SettingsEnums.ACTION_UNKNOWN; return SettingsEnums.ACTION_UNKNOWN;
} }
@@ -334,6 +342,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
removeActionBarToggleSwitch(); removeActionBarToggleSwitch();
} }
/**
* Returns the shortcut type list which has been checked by user.
*/
abstract int getUserShortcutTypes();
protected void updateToggleServiceTitle(SwitchPreference switchPreference) { protected void updateToggleServiceTitle(SwitchPreference switchPreference) {
switchPreference.setTitle(R.string.accessibility_service_master_switch_title); switchPreference.setTitle(R.string.accessibility_service_master_switch_title);
} }
@@ -658,6 +671,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
if (preference.isChecked()) { if (preference.isChecked()) {
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
mComponentName); mComponentName);
showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
} else { } else {
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes, AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
mComponentName); mComponentName);

View File

@@ -224,24 +224,22 @@ public class ToggleScreenMagnificationPreferenceFragment extends
@Override @Override
public Dialog onCreateDialog(int dialogId) { public Dialog onCreateDialog(int dialogId) {
final AlertDialog dialog;
switch (dialogId) { switch (dialogId) {
case DialogEnums.GESTURE_NAVIGATION_TUTORIAL: case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
return AccessibilityGestureNavigationTutorial return AccessibilityGestureNavigationTutorial
.showGestureNavigationTutorialDialog(getPrefContext()); .showGestureNavigationTutorialDialog(getPrefContext());
case DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL:
return AccessibilityGestureNavigationTutorial
.showAccessibilityButtonTutorialDialog(getPrefContext());
case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT: case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
final CharSequence dialogTitle = getPrefContext().getString( final CharSequence dialogTitle = getPrefContext().getString(
R.string.accessibility_shortcut_title, mPackageName); R.string.accessibility_shortcut_title, mPackageName);
final AlertDialog dialog = dialog = AccessibilityEditDialogUtils.showMagnificationEditShortcutDialog(
AccessibilityEditDialogUtils.showMagnificationEditShortcutDialog(
getPrefContext(), dialogTitle, getPrefContext(), dialogTitle,
this::callOnAlertDialogCheckboxClicked); this::callOnAlertDialogCheckboxClicked);
initializeDialogCheckBox(dialog); initializeDialogCheckBox(dialog);
return dialog; return dialog;
default:
return super.onCreateDialog(dialogId);
} }
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
} }
private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) { private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) {
@@ -408,18 +406,21 @@ public class ToggleScreenMagnificationPreferenceFragment extends
case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT: case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
return SettingsEnums.DIALOG_MAGNIFICATION_EDIT_SHORTCUT; return SettingsEnums.DIALOG_MAGNIFICATION_EDIT_SHORTCUT;
default: default:
return 0; return super.getDialogMetricsCategory(dialogId);
} }
} }
@Override
int getUserShortcutTypes() {
return getUserShortcutTypeFromSettings(getPrefContext());
}
@Override @Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) { protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
if (enabled && TextUtils.equals( if (enabled && TextUtils.equals(
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
preferenceKey)) { preferenceKey)) {
showDialog(AccessibilityUtil.isGestureNavigateEnabled(getPrefContext()) showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
? DialogEnums.GESTURE_NAVIGATION_TUTORIAL
: DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL);
} }
MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled); MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled);
} }
@@ -449,6 +450,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE);
if (preference.isChecked()) { if (preference.isChecked()) {
optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes); optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes);
showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
} else { } else {
optOutAllMagnificationValuesFromSettings(getPrefContext(), shortcutTypes); optOutAllMagnificationValuesFromSettings(getPrefContext(), shortcutTypes);
} }

View File

@@ -0,0 +1,89 @@
/*
* 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.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityGestureNavigationTutorial.createAccessibilityTutorialDialog;
import static com.android.settings.accessibility.AccessibilityGestureNavigationTutorial.createShortcutTutorialPages;
import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.appcompat.app.AlertDialog;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** Tests for {@link AccessibilityGestureNavigationTutorial}. */
@RunWith(RobolectricTestRunner.class)
public final class AccessibilityGestureNavigationTutorialTest {
private Context mContext;
private int mShortcutTypes;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mShortcutTypes = /* initial */ 0;
}
@Test(expected = IllegalArgumentException.class)
public void createTutorialPages_shortcutListIsEmpty_throwsException() {
createAccessibilityTutorialDialog(mContext, mShortcutTypes);
}
@Test
public void createTutorialPages_turnOnTripleTapShortcut_hasOnePage() {
mShortcutTypes |= UserShortcutType.TRIPLETAP;
final AlertDialog alertDialog =
createAccessibilityTutorialDialog(mContext, mShortcutTypes);
assertThat(createShortcutTutorialPages(mContext,
mShortcutTypes)).hasSize(/* expectedSize= */ 1);
assertThat(alertDialog).isNotNull();
}
@Test
public void createTutorialPages_turnOnSoftwareShortcut_hasOnePage() {
mShortcutTypes |= UserShortcutType.SOFTWARE;
final AlertDialog alertDialog =
createAccessibilityTutorialDialog(mContext, mShortcutTypes);
assertThat(createShortcutTutorialPages(mContext,
mShortcutTypes)).hasSize(/* expectedSize= */ 1);
assertThat(alertDialog).isNotNull();
}
@Test
public void createTutorialPages_turnOnSoftwareAndHardwareShortcuts_hasTwoPages() {
mShortcutTypes |= UserShortcutType.SOFTWARE;
mShortcutTypes |= UserShortcutType.HARDWARE;
final AlertDialog alertDialog =
createAccessibilityTutorialDialog(mContext, mShortcutTypes);
assertThat(createShortcutTutorialPages(mContext,
mShortcutTypes)).hasSize(/* expectedSize= */ 2);
assertThat(alertDialog).isNotNull();
}
}

View File

@@ -129,6 +129,11 @@ public class ToggleFeaturePreferenceFragmentTest {
return 0; return 0;
} }
@Override
int getUserShortcutTypes() {
return 0;
}
@Override @Override
public int getPreferenceScreenResId() { public int getPreferenceScreenResId() {
return R.xml.placeholder_prefs; return R.xml.placeholder_prefs;

View File

@@ -86,5 +86,10 @@ public class ToggleFeaturePreferenceFragmentTest {
public int getMetricsCategory() { public int getMetricsCategory() {
return 0; return 0;
} }
@Override
int getUserShortcutTypes() {
return 0;
}
} }
} }