Files
packages_apps_Settings/src/com/android/settings/accessibility/MagnificationModePreferenceController.java

324 lines
14 KiB
Java

/*
* Copyright (C) 2019 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.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.provider.Settings;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.util.Preconditions;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.DialogCreatable;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.utils.AnnotationSpan;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import java.util.ArrayList;
import java.util.List;
/** Controller that shows the magnification area mode summary and the preference click behavior. */
public class MagnificationModePreferenceController extends BasePreferenceController implements
DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState {
static final String PREF_KEY = "screen_magnification_mode";
static final String EXTRA_MODE = "mode";
private static final String TAG = MagnificationModePreferenceController.class.getSimpleName();
@Nullable
private DialogHelper mDialogHelper;
// The magnification mode in the dialog.
@MagnificationMode
private int mModeCache = MagnificationMode.NONE;
@Nullable
private Preference mModePreference;
@Nullable
private ShortcutPreference mLinkPreference;
@VisibleForTesting
@Nullable
ListView mMagnificationModesListView;
private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
public MagnificationModePreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
initModeInfos();
}
public void setDialogHelper(@NonNull DialogHelper dialogHelper) {
mDialogHelper = dialogHelper;
}
private void initModeInfos() {
mModeInfos.add(new MagnificationModeInfo(mContext.getText(
R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
R.drawable.a11y_magnification_mode_fullscreen, MagnificationMode.FULLSCREEN));
mModeInfos.add(new MagnificationModeInfo(
mContext.getText(R.string.accessibility_magnification_mode_dialog_option_window),
null, R.drawable.a11y_magnification_mode_window, MagnificationMode.WINDOW));
mModeInfos.add(new MagnificationModeInfo(
mContext.getText(R.string.accessibility_magnification_mode_dialog_option_switch),
mContext.getText(
R.string.accessibility_magnification_area_settings_mode_switch_summary),
R.drawable.a11y_magnification_mode_switch, MagnificationMode.ALL));
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@NonNull
@Override
public CharSequence getSummary() {
final int capabilities = MagnificationCapabilities.getCapabilities(mContext);
return MagnificationCapabilities.getSummary(mContext, capabilities);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
}
}
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
mModePreference = screen.findPreference(getPreferenceKey());
mLinkPreference = screen.findPreference(
ToggleScreenMagnificationPreferenceFragment.KEY_MAGNIFICATION_SHORTCUT_PREFERENCE);
Preconditions.checkNotNull(mModePreference).setOnPreferenceClickListener(preference -> {
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
Preconditions.checkNotNull(mDialogHelper).showDialog(
DialogEnums.DIALOG_MAGNIFICATION_MODE);
return true;
});
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putInt(EXTRA_MODE, mModeCache);
}
@NonNull
@Override
public Dialog onCreateDialog(int dialogId) {
return switch (dialogId) {
case DialogEnums.DIALOG_MAGNIFICATION_MODE -> createMagnificationModeDialog();
case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
createMagnificationTripleTapWarningDialog();
default -> throw new IllegalArgumentException(
"This only handles magnification mode and triple tap warning dialog");
};
}
@Override
public int getDialogMetricsCategory(int dialogId) {
return switch (dialogId) {
case DialogEnums.DIALOG_MAGNIFICATION_MODE ->
SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
default -> 0;
};
}
@NonNull
private ListView getMagnificationModesListView() {
return Preconditions.checkNotNull(mMagnificationModesListView);
}
@NonNull
private Dialog createMagnificationModeDialog() {
mMagnificationModesListView = AccessibilityDialogUtils.createSingleChoiceListView(
mContext, mModeInfos, this::onMagnificationModeSelected);
final View headerView = LayoutInflater.from(mContext).inflate(
R.layout.accessibility_dialog_header, getMagnificationModesListView(),
/* attachToRoot= */false);
final TextView textView = Preconditions.checkNotNull(headerView.findViewById(
R.id.accessibility_dialog_header_text_view));
textView.setText(
mContext.getString(R.string.accessibility_magnification_area_settings_message));
getMagnificationModesListView().addHeaderView(headerView, /* data= */null,
/* isSelectable= */false);
getMagnificationModesListView().setItemChecked(computeSelectionIndex(), /* value= */true);
final CharSequence title = mContext.getString(
R.string.accessibility_magnification_mode_dialog_title);
final CharSequence positiveBtnText = mContext.getString(R.string.save);
final CharSequence negativeBtnText = mContext.getString(R.string.cancel);
return AccessibilityDialogUtils.createCustomDialog(mContext, title,
getMagnificationModesListView(), positiveBtnText,
this::onMagnificationModeDialogPositiveButtonClicked,
negativeBtnText, /* negativeListener= */null);
}
@VisibleForTesting
void onMagnificationModeDialogPositiveButtonClicked(@NonNull DialogInterface dialogInterface,
int which) {
final int selectedIndex = getMagnificationModesListView().getCheckedItemPosition();
if (selectedIndex == AdapterView.INVALID_POSITION) {
Log.w(TAG, "Selected positive button with INVALID_POSITION index");
return;
}
mModeCache = ((MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(
selectedIndex)).mMagnificationMode;
// Do not save mode until user clicks positive button in triple tap warning dialog.
if (isTripleTapEnabled(mContext) && mModeCache != MagnificationMode.FULLSCREEN) {
Preconditions.checkNotNull(mDialogHelper).showDialog(
DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
} else { // Save mode (capabilities) value, don't need to show dialog to confirm.
updateCapabilitiesAndSummary(mModeCache);
}
}
private void updateCapabilitiesAndSummary(@MagnificationMode int mode) {
mModeCache = mode;
MagnificationCapabilities.setCapabilities(mContext, mModeCache);
Preconditions.checkNotNull(mModePreference).setSummary(
MagnificationCapabilities.getSummary(mContext, mModeCache));
}
private void onMagnificationModeSelected(@NonNull AdapterView<?> parent, @NonNull View view,
int position, long id) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(position);
if (modeInfo.mMagnificationMode == mModeCache) {
return;
}
mModeCache = modeInfo.mMagnificationMode;
}
private int computeSelectionIndex() {
final int modesSize = mModeInfos.size();
for (int i = 0; i < modesSize; i++) {
if (mModeInfos.get(i).mMagnificationMode == mModeCache) {
return i + getMagnificationModesListView().getHeaderViewsCount();
}
}
Log.w(TAG, "Can not find matching mode in mModeInfos");
return 0;
}
@VisibleForTesting
static boolean isTripleTapEnabled(@NonNull Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
}
@NonNull
private Dialog createMagnificationTripleTapWarningDialog() {
@SuppressWarnings({"InflateParams"})
final View contentView = LayoutInflater.from(mContext).inflate(
R.layout.magnification_triple_tap_warning_dialog, /* root= */ null);
final CharSequence title = mContext.getString(
R.string.accessibility_magnification_triple_tap_warning_title);
final CharSequence positiveBtnText = mContext.getString(
R.string.accessibility_magnification_triple_tap_warning_positive_button);
final CharSequence negativeBtnText = mContext.getString(
R.string.accessibility_magnification_triple_tap_warning_negative_button);
final Dialog dialog = AccessibilityDialogUtils.createCustomDialog(mContext, title,
contentView,
positiveBtnText, this::onMagnificationTripleTapWarningDialogPositiveButtonClicked,
negativeBtnText, this::onMagnificationTripleTapWarningDialogNegativeButtonClicked);
updateLinkInTripleTapWarningDialog(dialog, contentView);
return dialog;
}
private void updateLinkInTripleTapWarningDialog(@NonNull Dialog dialog,
@NonNull View contentView) {
final TextView messageView = contentView.findViewById(R.id.message);
// TODO(b/225682559): Need to remove performClick() after refactoring accessibility dialog.
final View.OnClickListener linkListener = view -> {
updateCapabilitiesAndSummary(mModeCache);
Preconditions.checkNotNull(mLinkPreference).performClick();
dialog.dismiss();
};
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
final CharSequence textWithLink = AnnotationSpan.linkify(mContext.getText(
R.string.accessibility_magnification_triple_tap_warning_message), linkInfo);
if (messageView != null) {
messageView.setText(textWithLink);
messageView.setMovementMethod(LinkMovementMethod.getInstance());
}
dialog.setContentView(contentView);
}
@VisibleForTesting
void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
@NonNull DialogInterface dialogInterface, int which) {
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
Preconditions.checkNotNull(mDialogHelper).showDialog(
DialogEnums.DIALOG_MAGNIFICATION_MODE);
}
@VisibleForTesting
void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
@NonNull DialogInterface dialogInterface, int which) {
updateCapabilitiesAndSummary(mModeCache);
}
@VisibleForTesting
static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
@MagnificationMode
public final int mMagnificationMode;
MagnificationModeInfo(@NonNull CharSequence title, @Nullable CharSequence summary,
@DrawableRes int drawableId, @MagnificationMode int magnificationMode) {
super(title, summary, drawableId);
mMagnificationMode = magnificationMode;
}
}
}