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

Commit 2b968139 authored by Daniel Norman's avatar Daniel Norman Committed by Chun-Ku Lin
Browse files

feat(HCT): Perform custom migration for HCT when restoring from backup

Sends a broadcast that is picked up by the same receiver in the Settings
app that handles migration for users during OTA.

Bug: 369906140
Test: atest SettingsHelperRestoreTest
Flag: com.android.graphics.hwui.flags.high_contrast_text_small_text_rect
Change-Id: I23ae51da085f9456233e97b15288e55bfd0939c4
parent 9d2f3764
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.hardware.display.ColorDisplayManager;
import android.icu.util.ULocale;
@@ -31,6 +33,7 @@ import android.media.AudioManager;
import android.media.RingtoneManager;
import android.media.Utils;
import android.net.Uri;
import android.os.Build;
import android.os.LocaleList;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -48,6 +51,7 @@ import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManage
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;

@@ -67,6 +71,9 @@ public class SettingsHelper {
    private static final int LONG_PRESS_POWER_FOR_ASSISTANT = 5;
    /** See frameworks/base/core/res/res/values/config.xml#config_keyChordPowerVolumeUp **/
    private static final int KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS = 2;
    @VisibleForTesting
    static final String HIGH_CONTRAST_TEXT_RESTORED_BROADCAST_ACTION =
            "com.android.settings.accessibility.ACTION_HIGH_CONTRAST_TEXT_RESTORED";

    private Context mContext;
    private AudioManager mAudioManager;
@@ -246,6 +253,23 @@ public class SettingsHelper {
                // Don't write it to setting. Let the broadcast receiver in
                // AccessibilityManagerService handle restore/merging logic.
                return;
            } else if (com.android.graphics.hwui.flags.Flags.highContrastTextSmallTextRect()
                    && Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED.equals(name)) {
                final boolean currentlyEnabled = Settings.Secure.getInt(
                        context.getContentResolver(),
                        Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1;
                final boolean enabledInRestore = value != null && Integer.parseInt(value) == 1;

                // If restoring from Android 15 or earlier and the user didn't already enable HCT
                // on this new device, then don't restore and trigger custom migration logic.
                final boolean needsCustomMigration = !currentlyEnabled
                        && restoredFromSdkInt < Build.VERSION_CODES.BAKLAVA
                        && enabledInRestore;
                if (needsCustomMigration) {
                    migrateHighContrastText(context);
                    return;
                }
                // fall through to the ordinary write to settings
            }

            // Default case: write the restored value to settings
@@ -523,6 +547,30 @@ public class SettingsHelper {
        }
    }

    private static void migrateHighContrastText(Context context) {
        final Intent intent = new Intent(HIGH_CONTRAST_TEXT_RESTORED_BROADCAST_ACTION)
                .setPackage(getSettingsAppPackage(context));
        context.sendBroadcastAsUser(intent, context.getUser(), null);
    }

    /**
     * Returns the System Settings application's package name
     */
    private static String getSettingsAppPackage(Context context) {
        String settingsAppPackage = null;
        PackageManager packageManager = context.getPackageManager();
        if (packageManager != null) {
            List<ResolveInfo> results = packageManager.queryIntentActivities(
                    new Intent(Settings.ACTION_SETTINGS),
                    PackageManager.MATCH_SYSTEM_ONLY);
            if (!results.isEmpty()) {
                settingsAppPackage = results.getFirst().activityInfo.applicationInfo.packageName;
            }
        }

        return !TextUtils.isEmpty(settingsAppPackage) ? settingsAppPackage : "com.android.settings";
    }

    /* package */ byte[] getLocaleData() {
        Configuration conf = mContext.getResources().getConfiguration();
        return conf.getLocales().toLanguageTags().getBytes();
+97 −4
Original line number Diff line number Diff line
@@ -26,15 +26,19 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.SettingsStringUtil;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.internal.util.test.BroadcastInterceptingContext;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -48,7 +52,8 @@ import java.util.concurrent.ExecutionException;
 */
@RunWith(AndroidJUnit4.class)
public class SettingsHelperRestoreTest {

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
    private static final float FLOAT_TOLERANCE = 0.01f;

    private Context mContext;
@@ -57,11 +62,99 @@ public class SettingsHelperRestoreTest {

    @Before
    public void setUp() {
        mContext = InstrumentationRegistry.getContext();
        mContext = InstrumentationRegistry.getInstrumentation().getContext();
        mContentResolver = mContext.getContentResolver();
        mSettingsHelper = new SettingsHelper(mContext);
    }

    @After
    public void cleanUp() {
        setDefaultAccessibilityDisplayMagnificationScale();
        Settings.Secure.putInt(mContentResolver,
                Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0);
        Settings.Secure.putString(mContentResolver, Settings.Secure.ACCESSIBILITY_QS_TARGETS, null);
        Settings.Secure.putString(mContentResolver,
                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
    }

    @Test
    public void restoreHighTextContrastEnabled_currentlyEnabled_enableInRestoredFromVanilla_dontSendNotification_hctKeepsEnabled()
            throws ExecutionException, InterruptedException {
        BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
                mContext);
        BroadcastInterceptingContext.FutureIntent futureIntent =
                interceptingContext.nextBroadcastIntent(
                        SettingsHelper.HIGH_CONTRAST_TEXT_RESTORED_BROADCAST_ACTION);
        mContentResolver = interceptingContext.getContentResolver();
        String settingName = Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED;
        Settings.Secure.putInt(mContentResolver, settingName, 1);

        mSettingsHelper.restoreValue(
                interceptingContext,
                mContentResolver,
                new ContentValues(2),
                Settings.Secure.getUriFor(settingName),
                settingName,
                String.valueOf(1),
                Build.VERSION_CODES.VANILLA_ICE_CREAM);

        futureIntent.assertNotReceived();
        assertThat(Settings.Secure.getInt(mContentResolver, settingName, 0)).isEqualTo(1);
    }

    @EnableFlags(com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT)
    @Test
    public void restoreHighTextContrastEnabled_currentlyDisabled_enableInRestoredFromVanilla_sendNotification_hctKeepsDisabled()
            throws ExecutionException, InterruptedException {
        BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
                mContext);
        BroadcastInterceptingContext.FutureIntent futureIntent =
                interceptingContext.nextBroadcastIntent(
                        SettingsHelper.HIGH_CONTRAST_TEXT_RESTORED_BROADCAST_ACTION);
        mContentResolver = interceptingContext.getContentResolver();
        String settingName = Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED;
        Settings.Secure.putInt(mContentResolver, settingName, 0);

        mSettingsHelper.restoreValue(
                interceptingContext,
                mContentResolver,
                new ContentValues(2),
                Settings.Secure.getUriFor(settingName),
                settingName,
                String.valueOf(1),
                Build.VERSION_CODES.VANILLA_ICE_CREAM);

        Intent intentReceived = futureIntent.get();
        assertThat(intentReceived).isNotNull();
        assertThat(intentReceived.getPackage()).isNotNull();
        assertThat(Settings.Secure.getInt(mContentResolver, settingName, 0)).isEqualTo(0);
    }

    @Test
    public void restoreHighTextContrastEnabled_currentlyDisabled_enableInRestoredFromAfterVanilla_dontSendNotification_hctShouldEnabled()
            throws ExecutionException, InterruptedException {
        BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
                mContext);
        BroadcastInterceptingContext.FutureIntent futureIntent =
                interceptingContext.nextBroadcastIntent(
                        SettingsHelper.HIGH_CONTRAST_TEXT_RESTORED_BROADCAST_ACTION);
        mContentResolver = interceptingContext.getContentResolver();
        String settingName = Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED;
        Settings.Secure.putInt(mContentResolver, settingName, 0);

        mSettingsHelper.restoreValue(
                interceptingContext,
                mContentResolver,
                new ContentValues(2),
                Settings.Secure.getUriFor(settingName),
                settingName,
                String.valueOf(1),
                Build.VERSION_CODES.BAKLAVA);

        futureIntent.assertNotReceived();
        assertThat(Settings.Secure.getInt(mContentResolver, settingName, 0)).isEqualTo(1);
    }

    /** Tests for {@link Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. */
    @Test
    public void