Files
app_Settings/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
Roy Chou 004238d7f8 fix(text preference): fix preview block ui broken in SUW
As previous cl ag/25185014 we increased the preview block horizontal padding when landscape mode. However, in setup wizard it uses GlifPreferenceLayout so the settings page only has half screen width when landscape mode, so the preview block ui is squished due to limited width. Also, setup wizard package has overlay the paddings to larger than our prevoius adjust. Therefore, we rollback the changes in accessibility_text_reading_preview.xml to get the default padding, then add checker to increase the paddings if needed at runtime.

Bug: 309590083
Test: manually
Test: atest TextReadingPreviewPreferenceTest
Test: atest TextReadingPreferenceFragmentForSetupWizardTest
Change-Id: Ib907f4182eed272b84a4ab6208ea2d8a89ba96c4
2023-11-20 03:10:33 +00:00

317 lines
12 KiB
Java

/*
* Copyright (C) 2022 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.FONT_SIZE_COMPONENT_NAME;
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
import android.app.Activity;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.IntDef;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.common.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Accessibility settings for adjusting the system features which are related to the reading. For
* example, bold text, high contrast text, display size, font size and so on.
*/
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class TextReadingPreferenceFragment extends DashboardFragment {
public static final String EXTRA_LAUNCHED_FROM = "launched_from";
private static final String TAG = "TextReadingPreferenceFragment";
private static final String SETUP_WIZARD_PACKAGE = "setupwizard";
static final String FONT_SIZE_KEY = "font_size";
static final String DISPLAY_SIZE_KEY = "display_size";
static final String BOLD_TEXT_KEY = "toggle_force_bold_text";
static final String HIGH_TEXT_CONTRAST_KEY = "toggle_high_text_contrast_preference";
static final String RESET_KEY = "reset";
static final String PREVIEW_KEY = "preview";
private static final String NEED_RESET_SETTINGS = "need_reset_settings";
private static final String LAST_PREVIEW_INDEX = "last_preview_index";
private static final int UNKNOWN_INDEX = -1;
private FontWeightAdjustmentPreferenceController mFontWeightAdjustmentController;
private TextReadingPreviewController mPreviewController;
private int mEntryPoint = EntryPoint.UNKNOWN_ENTRY;
/**
* The entry point which launches the {@link TextReadingPreferenceFragment}.
*
* <p>This should only be used for logging.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
EntryPoint.UNKNOWN_ENTRY,
EntryPoint.SUW_VISION_SETTINGS,
EntryPoint.SUW_ANYTHING_ELSE,
EntryPoint.DISPLAY_SETTINGS,
EntryPoint.ACCESSIBILITY_SETTINGS,
})
@interface EntryPoint {
int UNKNOWN_ENTRY = 0;
int SUW_VISION_SETTINGS = 1;
int SUW_ANYTHING_ELSE = 2;
int DISPLAY_SETTINGS = 3;
int ACCESSIBILITY_SETTINGS = 4;
}
@VisibleForTesting
List<ResetStateListener> mResetStateListeners;
@VisibleForTesting
boolean mNeedResetSettings;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNeedResetSettings = false;
mResetStateListeners = getResetStateListeners();
if (savedInstanceState != null) {
if (savedInstanceState.getBoolean(NEED_RESET_SETTINGS)) {
mResetStateListeners.forEach(ResetStateListener::resetState);
}
if (savedInstanceState.containsKey(LAST_PREVIEW_INDEX)) {
final int lastPreviewIndex = savedInstanceState.getInt(LAST_PREVIEW_INDEX);
if (lastPreviewIndex != UNKNOWN_INDEX) {
mPreviewController.setCurrentItem(lastPreviewIndex);
}
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final View rootView = getActivity().getWindow().peekDecorView();
if (rootView != null) {
rootView.setAccessibilityPaneTitle(getString(
R.string.accessibility_text_reading_options_title));
}
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_text_reading_options;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_TEXT_READING_OPTIONS;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
updateEntryPoint();
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final FontSizeData fontSizeData = new FontSizeData(context);
final DisplaySizeData displaySizeData = createDisplaySizeData(context);
mPreviewController = new TextReadingPreviewController(context, PREVIEW_KEY, fontSizeData,
displaySizeData);
mPreviewController.setEntryPoint(mEntryPoint);
controllers.add(mPreviewController);
final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
context, FONT_SIZE_KEY, fontSizeData) {
@Override
ComponentName getTileComponentName() {
return FONT_SIZE_COMPONENT_NAME;
}
@Override
CharSequence getTileTooltipContent() {
return context.getText(
R.string.accessibility_font_scaling_auto_added_qs_tooltip_content);
}
};
final String[] labelArray = new String[fontSizeData.getValues().size()];
for (int i = 0; i < labelArray.length; i++) {
labelArray[i] =
context.getResources().getString(
com.android.settingslib.R.string.font_scale_percentage,
(int) (fontSizeData.getValues().get(i) * 100)
);
}
fontSizeController.setProgressStateLabels(labelArray);
fontSizeController.setInteractionListener(mPreviewController);
getSettingsLifecycle().addObserver(fontSizeController);
controllers.add(fontSizeController);
final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
context, DISPLAY_SIZE_KEY, displaySizeData) {
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileTooltipContent() {
return null;
}
};
displaySizeController.setInteractionListener(mPreviewController);
controllers.add(displaySizeController);
mFontWeightAdjustmentController =
new FontWeightAdjustmentPreferenceController(context, BOLD_TEXT_KEY);
mFontWeightAdjustmentController.setEntryPoint(mEntryPoint);
controllers.add(mFontWeightAdjustmentController);
final HighTextContrastPreferenceController highTextContrastController =
new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY);
highTextContrastController.setEntryPoint(mEntryPoint);
controllers.add(highTextContrastController);
final TextReadingResetController resetController =
new TextReadingResetController(context, RESET_KEY,
v -> showDialog(DialogEnums.DIALOG_RESET_SETTINGS));
resetController.setEntryPoint(mEntryPoint);
resetController.setVisible(!WizardManagerHelper.isAnySetupWizard(getIntent()));
controllers.add(resetController);
return controllers;
}
@Override
public Dialog onCreateDialog(int dialogId) {
if (dialogId == DialogEnums.DIALOG_RESET_SETTINGS) {
return new AlertDialog.Builder(getPrefContext())
.setTitle(R.string.accessibility_text_reading_confirm_dialog_title)
.setMessage(R.string.accessibility_text_reading_confirm_dialog_message)
.setPositiveButton(
R.string.accessibility_text_reading_confirm_dialog_reset_button,
this::onPositiveButtonClicked)
.setNegativeButton(R.string.cancel, /* listener= */ null)
.create();
}
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
}
@Override
public int getDialogMetricsCategory(int dialogId) {
if (dialogId == DialogEnums.DIALOG_RESET_SETTINGS) {
return SettingsEnums.DIALOG_RESET_SETTINGS;
}
return super.getDialogMetricsCategory(dialogId);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mNeedResetSettings) {
outState.putBoolean(NEED_RESET_SETTINGS, true);
}
outState.putInt(LAST_PREVIEW_INDEX, mPreviewController.getCurrentItem());
}
@Override
public void onStart() {
super.onStart();
}
protected boolean isCallingFromAnythingElseEntryPoint() {
final Activity activity = getActivity();
final String callingPackage = activity != null ? activity.getCallingPackage() : null;
return callingPackage != null && callingPackage.contains(SETUP_WIZARD_PACKAGE);
}
@VisibleForTesting
DisplaySizeData createDisplaySizeData(Context context) {
return new DisplaySizeData(context);
}
private void updateEntryPoint() {
final Bundle bundle = getArguments();
if (bundle != null && bundle.containsKey(EXTRA_LAUNCHED_FROM)) {
mEntryPoint = bundle.getInt(EXTRA_LAUNCHED_FROM, EntryPoint.UNKNOWN_ENTRY);
return;
}
mEntryPoint = isCallingFromAnythingElseEntryPoint()
? EntryPoint.SUW_ANYTHING_ELSE : EntryPoint.UNKNOWN_ENTRY;
}
private void onPositiveButtonClicked(DialogInterface dialog, int which) {
// To avoid showing the dialog again, probably the onDetach() of SettingsDialogFragment
// was interrupted by unexpectedly recreating the activity.
removeDialog(DialogEnums.DIALOG_RESET_SETTINGS);
if (mFontWeightAdjustmentController.isChecked()) {
// TODO(b/228956791): Consider replacing or removing it once the root cause is
// clarified and the better method is available.
// Probably has the race condition issue between "Bold text" and the other features
// including "Display Size", “Font Size” if they would be enabled at the same time,
// so our workaround is that the “Bold text” would be reset first and then do the
// remaining to avoid flickering problem.
mNeedResetSettings = true;
mFontWeightAdjustmentController.resetState();
} else {
mResetStateListeners.forEach(ResetStateListener::resetState);
}
Toast.makeText(getPrefContext(), R.string.accessibility_text_reading_reset_message,
Toast.LENGTH_SHORT).show();
}
private List<ResetStateListener> getResetStateListeners() {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
getPreferenceControllers().forEach(controllers::addAll);
return controllers.stream().filter(c -> c instanceof ResetStateListener).map(
c -> (ResetStateListener) c).collect(Collectors.toList());
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.accessibility_text_reading_options);
}