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

Commit 58089c39 authored by Daniel Norman's avatar Daniel Norman Committed by Android (Google) Code Review
Browse files

Merge changes Id7f9e6de,I73a5fcf3 into main

* changes:
  Clears the default service from A11Y_SHORTCUT B&R.
  Perform merging for A11Y_SHORTCUT B&R.
parents 35d8ad01 05a2f1c6
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -153,6 +153,16 @@ flag {
    }
}

flag {
    name: "restore_a11y_shortcut_target_service"
    namespace: "accessibility"
    description: "Perform merging and other bug fixes for SettingsProvider restore of ACCESSIBILITY_SHORTCUT_TARGET_SERVICES secure setting"
    bug: "341374402"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "support_system_pinch_zoom_opt_out_apis"
    namespace: "accessibility"
+47 −28
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AlertDialog;
@@ -240,6 +241,7 @@ public class AccessibilityShortcutController {
    /**
     * Called when the accessibility shortcut is activated
     */
    @SuppressLint("MissingPermission")
    public void performAccessibilityShortcut() {
        Slog.d(TAG, "Accessibility shortcut activated");
        final ContentResolver cr = mContext.getContentResolver();
@@ -274,6 +276,9 @@ public class AccessibilityShortcutController {
                    cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStatus.SHOWN,
                    userId);
        } else {
            if (Flags.restoreA11yShortcutTargetService()) {
                enableDefaultHardwareShortcut(userId);
            }
            playNotificationTone();
            if (mAlertDialog != null) {
                mAlertDialog.dismiss();
@@ -349,34 +354,7 @@ public class AccessibilityShortcutController {
                .setMessage(getShortcutWarningMessage(targets))
                .setCancelable(false)
                .setNegativeButton(R.string.accessibility_shortcut_on,
                        (DialogInterface d, int which) -> {
                            String targetServices = Settings.Secure.getStringForUser(
                                    mContext.getContentResolver(),
                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
                            String defaultService = mContext.getString(
                                    R.string.config_defaultAccessibilityService);
                            // If the targetServices is null, means the user enables a
                            // shortcut for the default service by triggering the volume keys
                            // shortcut in the SUW instead of intentionally configuring the
                            // shortcut on UI.
                            if (targetServices == null && !TextUtils.isEmpty(defaultService)) {
                                // The defaultService in the string resource could be a shorten
                                // form like com.google.android.marvin.talkback/.TalkBackService.
                                // Converts it to the componentName for consistency before saving
                                // to the Settings.
                                final ComponentName configDefaultService =
                                        ComponentName.unflattenFromString(defaultService);
                                if (Flags.migrateEnableShortcuts()) {
                                    am.enableShortcutsForTargets(true, HARDWARE,
                                            Set.of(configDefaultService.flattenToString()), userId);
                                } else {
                                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
                                            Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                                            configDefaultService.flattenToString(),
                                            userId);
                                }
                            }
                        })
                        (DialogInterface d, int which) -> enableDefaultHardwareShortcut(userId))
                .setPositiveButton(R.string.accessibility_shortcut_off,
                        (DialogInterface d, int which) -> {
                            Set<String> targetServices =
@@ -509,6 +487,47 @@ public class AccessibilityShortcutController {
        }
    }

    /**
     * Writes {@link R.string#config_defaultAccessibilityService} to the
     * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE} Setting if
     * that Setting is currently {@code null}.
     *
     * <p>If {@code ACCESSIBILITY_SHORTCUT_TARGET_SERVICE} is {@code null} then the
     * user triggered the shortcut during Setup Wizard <i>before</i> directly
     * enabling the shortcut in the Settings UI of Setup Wizard.
     */
    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
    private void enableDefaultHardwareShortcut(int userId) {
        final AccessibilityManager accessibilityManager = mFrameworkObjectProvider
                .getAccessibilityManagerInstance(mContext);
        final String targetServices = Settings.Secure.getStringForUser(
                mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
        if (targetServices != null) {
            // Do not write if the Setting was already configured.
            return;
        }
        final String defaultService = mContext.getString(
                R.string.config_defaultAccessibilityService);
        // The defaultService in the string resource could be a shortened
        // form: "com.android.accessibility.package/.MyService". Convert it to
        // the component name form for consistency before writing to the Setting.
        final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
                ? null : ComponentName.unflattenFromString(defaultService);
        if (defaultServiceComponent == null) {
            // Default service is invalid, so nothing we can do here.
            return;
        }
        if (Flags.migrateEnableShortcuts()) {
            accessibilityManager.enableShortcutsForTargets(true, HARDWARE,
                    Set.of(defaultServiceComponent.flattenToString()), userId);
        } else {
            Settings.Secure.putStringForUser(mContext.getContentResolver(),
                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                    defaultServiceComponent.flattenToString(), userId);
        }
    }

    private boolean performTtsPrompt(AlertDialog alertDialog) {
        final String serviceName = getShortcutFeatureDescription(false /* no summary */);
        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+36 −0
Original line number Diff line number Diff line
@@ -633,6 +633,42 @@ public class AccessibilityShortcutControllerTest {
        verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
    }

    @Test
    @EnableFlags({
            Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS,
            Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE})
    public void testOnAccessibilityShortcut_settingNull_dialogShown_enablesDefaultShortcut()
            throws Exception {
        configureDefaultAccessibilityService();
        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
                AccessibilityShortcutController.DialogStatus.SHOWN);
        // Setting is only `null` during SUW.
        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
        getController().performAccessibilityShortcut();

        verify(mAccessibilityManagerService).enableShortcutsForTargets(
                eq(true), eq(HARDWARE), mListCaptor.capture(), anyInt());
        assertThat(mListCaptor.getValue()).containsExactly(SERVICE_NAME_STRING);
        verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
    }

    @Test
    @EnableFlags(Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
    public void testOnAccessibilityShortcut_settingNull_dialogShown_writesDefaultSetting()
            throws Exception {
        configureDefaultAccessibilityService();
        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
                AccessibilityShortcutController.DialogStatus.SHOWN);
        // Setting is only `null` during SUW.
        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
        getController().performAccessibilityShortcut();

        assertThat(Settings.Secure.getString(mContentResolver,
                ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEqualTo(SERVICE_NAME_STRING);
        verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
    }

    @Test
    public void getFrameworkFeatureMap_shouldBeUnmodifiable() {
        final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
+7 −1
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ public class SettingsHelper {
    private static final ArraySet<String> sBroadcastOnRestore;
    private static final ArraySet<String> sBroadcastOnRestoreSystemUI;
    static {
        sBroadcastOnRestore = new ArraySet<String>(9);
        sBroadcastOnRestore = new ArraySet<String>(12);
        sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
        sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
        sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -99,6 +99,7 @@ public class SettingsHelper {
        sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
        sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
        sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
        sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
        sBroadcastOnRestore.add(Settings.Secure.SCREEN_RESOLUTION_MODE);
        sBroadcastOnRestoreSystemUI = new ArraySet<String>(2);
        sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES);
@@ -240,6 +241,11 @@ public class SettingsHelper {
                // Don't write it to setting. Let the broadcast receiver in
                // AccessibilityManagerService handle restore/merging logic.
                return;
            } else if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()
                    && Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.equals(name)) {
                // Don't write it to setting. Let the broadcast receiver in
                // AccessibilityManagerService handle restore/merging logic.
                return;
            }

            // Default case: write the restored value to settings
+35 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ 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;

@@ -35,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.BroadcastInterceptingContext;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -48,6 +51,10 @@ 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;
@@ -202,4 +209,32 @@ public class SettingsHelperRestoreTest {
                Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, /* defaultValue= */ 0))
                .isEqualTo(Build.VERSION.SDK_INT);
    }

    @Test
    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
    public void restoreAccessibilityShortcutTargetService_broadcastSent()
            throws ExecutionException, InterruptedException {
        BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
                mContext);
        final String settingName = Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
        final String restoredValue = "com.android.a11y/Service";
        BroadcastInterceptingContext.FutureIntent futureIntent =
                interceptingContext.nextBroadcastIntent(Intent.ACTION_SETTING_RESTORED);

        mSettingsHelper.restoreValue(
                interceptingContext,
                mContentResolver,
                new ContentValues(2),
                Settings.Secure.getUriFor(settingName),
                settingName,
                restoredValue,
                Build.VERSION.SDK_INT);

        Intent intentReceived = futureIntent.get();
        assertThat(intentReceived.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE))
                .isEqualTo(restoredValue);
        assertThat(intentReceived.getIntExtra(
                Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, /* defaultValue= */ 0))
                .isEqualTo(Build.VERSION.SDK_INT);
    }
}
Loading