Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fa6e7df authored by Menghan Li's avatar Menghan Li Committed by Android (Google) Code Review
Browse files

Merge "Refactor AccessibilityControlTimeoutPreferenceFragment to improve maintainability"

parents 3db36eb5 236a3762
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -18,12 +18,10 @@
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:title="@string/accessibility_control_timeout_preference_title"
    android:persistent="false" >
    android:title="@string/accessibility_control_timeout_preference_title">

    <com.android.settingslib.widget.TopIntroPreference
        android:key="accessibility_control_timeout_intro"
        android:persistent="false"
        android:title="@string/accessibility_control_timeout_preference_intro_text"/>

    <com.android.settingslib.widget.IllustrationPreference
@@ -33,32 +31,31 @@
    <com.android.settingslib.widget.SelectorWithWidgetPreference
        android:key="accessibility_control_timeout_default"
        android:title="@string/accessibility_timeout_default"
        android:persistent="false" />
        settings:controller="com.android.settings.accessibility.AccessibilityTimeoutController"/>

    <com.android.settingslib.widget.SelectorWithWidgetPreference
        android:key="accessibility_control_timeout_10secs"
        android:title="@string/accessibility_timeout_10secs"
        android:persistent="false" />
        settings:controller="com.android.settings.accessibility.AccessibilityTimeoutController"/>

    <com.android.settingslib.widget.SelectorWithWidgetPreference
        android:key="accessibility_control_timeout_30secs"
        android:title="@string/accessibility_timeout_30secs"
        android:persistent="false" />
        settings:controller="com.android.settings.accessibility.AccessibilityTimeoutController"/>

    <com.android.settingslib.widget.SelectorWithWidgetPreference
        android:key="accessibility_control_timeout_1min"
        android:title="@string/accessibility_timeout_1min"
        android:persistent="false" />
        settings:controller="com.android.settings.accessibility.AccessibilityTimeoutController"/>

    <com.android.settingslib.widget.SelectorWithWidgetPreference
        android:key="accessibility_control_timeout_2mins"
        android:title="@string/accessibility_timeout_2mins"
        android:persistent="false" />
        settings:controller="com.android.settings.accessibility.AccessibilityTimeoutController"/>

    <com.android.settings.accessibility.AccessibilityFooterPreference
        android:key="accessibility_control_timeout_footer"
        android:title="@string/accessibility_control_timeout_preference_summary"
        android:persistent="false"
        android:selectable="false"
        settings:searchable="false"
        settings:controller="com.android.settings.accessibility.AccessibilityControlTimeoutFooterPreferenceController"/>
+2 −68
Original line number Diff line number Diff line
@@ -17,55 +17,17 @@
package com.android.settings.accessibility;

import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;

import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;

import java.util.ArrayList;
import java.util.List;

/** Settings fragment containing accessibility control timeout preference. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public final class AccessibilityControlTimeoutPreferenceFragment extends DashboardFragment
        implements AccessibilityTimeoutController.OnChangeListener {
public final class AccessibilityControlTimeoutPreferenceFragment extends DashboardFragment {

    static final String TAG = "AccessibilityControlTimeoutPreferenceFragment";
    private static final List<AbstractPreferenceController> sControllers = new ArrayList<>();

    @Override
    public void onCheckedChanged(Preference preference) {
        for (AbstractPreferenceController controller : sControllers) {
            controller.updateState(preference);
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        for (AbstractPreferenceController controller :
                buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
            ((AccessibilityTimeoutController)controller).setOnChangeListener(this);
        }
    }

    @Override
    public void onPause() {
        super.onPause();

        for (AbstractPreferenceController controller :
                buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
            ((AccessibilityTimeoutController)controller).setOnChangeListener(null);
        }
    }

    @Override
    public int getMetricsCategory() {
@@ -82,39 +44,11 @@ public final class AccessibilityControlTimeoutPreferenceFragment extends Dashboa
        return R.xml.accessibility_control_timeout_settings;
    }

    @Override
    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
        return buildPreferenceControllers(context, getSettingsLifecycle());
    }

    @Override
    public int getHelpResource() {
        return R.string.help_url_timeout;
    }

    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
            Lifecycle lifecycle) {
        if (sControllers.size() == 0) {
            Resources resources = context.getResources();

            String[] timeoutKeys = resources.getStringArray(
                    R.array.accessibility_timeout_control_selector_keys);

            for (int i=0; i < timeoutKeys.length; i++) {
                sControllers.add(new AccessibilityTimeoutController(
                        context, lifecycle, timeoutKeys[i]));
            }
        }
        return sControllers;
    }

    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
            new BaseSearchIndexProvider(R.xml.accessibility_control_timeout_settings) {

                @Override
                public List<AbstractPreferenceController> createPreferenceControllers(
                        Context context) {
                    return buildPreferenceControllers(context, null);
                }
            };
            new BaseSearchIndexProvider(R.xml.accessibility_control_timeout_settings);
}
+61 −99
Original line number Diff line number Diff line
@@ -19,157 +19,119 @@ package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;

import androidx.lifecycle.LifecycleObserver;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.widget.SelectorWithWidgetPreference;

import com.google.common.primitives.Ints;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Controller class that control accessibility time out settings.
 */
public class AccessibilityTimeoutController extends AbstractPreferenceController implements
        LifecycleObserver, SelectorWithWidgetPreference.OnClickListener, PreferenceControllerMixin {
    static final String CONTENT_TIMEOUT_SETTINGS_SECURE =
            Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS;
    static final String CONTROL_TIMEOUT_SETTINGS_SECURE =
            Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS;
/** Controller class that control accessibility timeout settings. */
public class AccessibilityTimeoutController extends BasePreferenceController implements
        LifecycleObserver, OnStart, OnStop , SelectorWithWidgetPreference.OnClickListener {

    private static final List<String> ACCESSIBILITY_TIMEOUT_FEATURE_KEYS = Arrays.asList(
            Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
            Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS
    );

    // pair the preference key and timeout value.
    private final Map<String, Integer> mAccessibilityTimeoutKeyToValueMap = new HashMap<>();

    // RadioButtonPreference key, each preference represent a timeout value.
    private final String mPreferenceKey;
    private final ContentResolver mContentResolver;
    private final Resources mResources;
    private OnChangeListener mOnChangeListener;
    private SelectorWithWidgetPreference mPreference;
    private int mAccessibilityUiTimeoutValue;
    private AccessibilitySettingsContentObserver mSettingsContentObserver;

    public AccessibilityTimeoutController(Context context, Lifecycle lifecycle,
            String preferenceKey) {
        super(context);

    public AccessibilityTimeoutController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mContentResolver = context.getContentResolver();
        mResources = context.getResources();

        if (lifecycle != null) {
            lifecycle.addObserver(this);
        }
        mPreferenceKey = preferenceKey;
    }

    protected static int getSecureAccessibilityTimeoutValue(ContentResolver resolver, String name) {
        String timeOutSec = Settings.Secure.getString(resolver, name);
        if (timeOutSec == null) {
            return 0;
        }
        Integer timeOutValue = Ints.tryParse(timeOutSec);
        return timeOutValue == null ? 0 : timeOutValue;
    }

    public void setOnChangeListener(OnChangeListener listener) {
        mOnChangeListener = listener;
    }

    private Map<String, Integer> getTimeoutValueToKeyMap() {
        if (mAccessibilityTimeoutKeyToValueMap.size() == 0) {

            String[] timeoutKeys = mResources.getStringArray(
                    R.array.accessibility_timeout_control_selector_keys);

            int[] timeoutValues = mResources.getIntArray(
                    R.array.accessibility_timeout_selector_values);

            final int timeoutValueCount = timeoutValues.length;
            for (int i = 0; i < timeoutValueCount; i++) {
                mAccessibilityTimeoutKeyToValueMap.put(timeoutKeys[i], timeoutValues[i]);
            }
        }
        return mAccessibilityTimeoutKeyToValueMap;
        mSettingsContentObserver = new AccessibilitySettingsContentObserver(
                new Handler(Looper.getMainLooper()));
        mSettingsContentObserver.registerKeysToObserverCallback(ACCESSIBILITY_TIMEOUT_FEATURE_KEYS,
                key -> updateState(mPreference));
    }

    private void putSecureString(String name, String value) {
        Settings.Secure.putString(mContentResolver, name, value);
    @VisibleForTesting
    AccessibilityTimeoutController(Context context, String preferenceKey,
            AccessibilitySettingsContentObserver contentObserver) {
        this(context, preferenceKey);
        mSettingsContentObserver = contentObserver;
    }

    private void handlePreferenceChange(String value) {
        // save value to both content and control timeout setting.
        putSecureString(Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, value);
        putSecureString(Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, value);
    @Override
    public void onStart() {
        mSettingsContentObserver.register(mContentResolver);
    }

    @Override
    public boolean isAvailable() {
        return true;
    public void onStop() {
        mSettingsContentObserver.unregister(mContentResolver);
    }

    @Override
    public String getPreferenceKey() {
        return mPreferenceKey;
    public int getAvailabilityStatus() {
        return AVAILABLE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);

        mPreference = (SelectorWithWidgetPreference)
                screen.findPreference(getPreferenceKey());
        mPreference = screen.findPreference(getPreferenceKey());
        mPreference.setOnClickListener(this);
    }

    @Override
    public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
        int value = getTimeoutValueToKeyMap().get(mPreferenceKey);
        handlePreferenceChange(String.valueOf(value));
        if (mOnChangeListener != null) {
            mOnChangeListener.onCheckedChanged(mPreference);
        }
    }

    private int getAccessibilityTimeoutValue() {
        // get accessibility control timeout value
        int timeoutValue = getSecureAccessibilityTimeoutValue(mContentResolver,
                CONTROL_TIMEOUT_SETTINGS_SECURE);
        return timeoutValue;
    }
        final String value = String.valueOf(getTimeoutValueToKeyMap().get(mPreferenceKey));

    protected void updatePreferenceCheckedState(int value) {
        if (mAccessibilityUiTimeoutValue == value) {
            mPreference.setChecked(true);
        }
        // save value to both content and control timeout setting.
        Settings.Secure.putString(mContentResolver,
                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, value);
        Settings.Secure.putString(mContentResolver,
                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, value);
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);

        mAccessibilityUiTimeoutValue = getAccessibilityTimeoutValue();
        mAccessibilityUiTimeoutValue = AccessibilityTimeoutUtils.getSecureAccessibilityTimeoutValue(
                mContentResolver);

        // reset RadioButton
        mPreference.setChecked(false);
        int preferenceValue = getTimeoutValueToKeyMap().get(mPreference.getKey());
        updatePreferenceCheckedState(preferenceValue);
        final int preferenceValue = getTimeoutValueToKeyMap().get(mPreference.getKey());
        if (mAccessibilityUiTimeoutValue == preferenceValue) {
            mPreference.setChecked(true);
        }
    }

    /**
     * Listener interface handles checked event.
     */
    public interface OnChangeListener {
        /**
         * A hook that is called when preference checked.
         */
        void onCheckedChanged(Preference preference);
    private Map<String, Integer> getTimeoutValueToKeyMap() {
        if (mAccessibilityTimeoutKeyToValueMap.size() == 0) {
            String[] timeoutKeys = mResources.getStringArray(
                    R.array.accessibility_timeout_control_selector_keys);
            final int[] timeoutValues = mResources.getIntArray(
                    R.array.accessibility_timeout_selector_values);
            final int timeoutValueCount = timeoutValues.length;
            for (int i = 0; i < timeoutValueCount; i++) {
                mAccessibilityTimeoutKeyToValueMap.put(timeoutKeys[i], timeoutValues[i]);
            }
        }
        return mAccessibilityTimeoutKeyToValueMap;
    }
}
+13 −6
Original line number Diff line number Diff line
@@ -16,17 +16,25 @@

package com.android.settings.accessibility;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;

import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;

import com.google.common.primitives.Ints;

/** Preference controller for accessibility timeout. */
public class AccessibilityTimeoutPreferenceController extends BasePreferenceController {

    private final ContentResolver mContentResolver;
    private final Resources mResources;

    public AccessibilityTimeoutPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mContentResolver = mContext.getContentResolver();
        mResources = mContext.getResources();
    }

    @Override
@@ -36,14 +44,13 @@ public class AccessibilityTimeoutPreferenceController extends BasePreferenceCont

    @Override
    public CharSequence getSummary() {
        final String[] timeoutSummarys = mContext.getResources().getStringArray(
        final String[] timeoutSummaries = mResources.getStringArray(
                R.array.accessibility_timeout_summaries);
        final int[] timeoutValues = mContext.getResources().getIntArray(
        final int[] timeoutValues = mResources.getIntArray(
                R.array.accessibility_timeout_selector_values);
        final int timeoutValue = AccessibilityTimeoutController.getSecureAccessibilityTimeoutValue(
                mContext.getContentResolver(),
                AccessibilityTimeoutController.CONTROL_TIMEOUT_SETTINGS_SECURE);
        final int timeoutValue = AccessibilityTimeoutUtils.getSecureAccessibilityTimeoutValue(
                mContentResolver);
        final int idx = Ints.indexOf(timeoutValues, timeoutValue);
        return timeoutSummarys[idx == -1 ? 0 : idx];
        return timeoutSummaries[idx == -1 ? 0 : idx];
    }
}
+44 −0
Original line number Diff line number Diff line
/*
 * 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 android.content.ContentResolver;
import android.provider.Settings;

import com.google.common.primitives.Ints;

/** Provides utility methods to accessibility timeout. */
public final class AccessibilityTimeoutUtils {

    /**
     * Gets accessibility control timeout value.
     *
     * @param resolver the resolver to use
     * @return accessibility control timeout value
     */
    public static int getSecureAccessibilityTimeoutValue(ContentResolver resolver) {
        final String timeOutSec = Settings.Secure.getString(resolver,
                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
        if (timeOutSec == null) {
            return 0;
        }
        Integer timeOutValue = Ints.tryParse(timeOutSec);
        return timeOutValue == null ? 0 : timeOutValue;
    }

    private AccessibilityTimeoutUtils(){}
}
Loading