DragToEdit Dynaimc Title

Bug: 323388734
Test: atest EditShortcutsPreferenceFragmentTest
Flag: aconfig edit_shortcut_dynamic_title true

Change-Id: I74785054e4f846db04d13a54bd6695e4690f5b8b
diff --git a/res/values/accessibility_shortcut_keys.xml b/res/values/accessibility_shortcut_keys.xml
index 0d409a8..4992a54 100644
--- a/res/values/accessibility_shortcut_keys.xml
+++ b/res/values/accessibility_shortcut_keys.xml
@@ -16,6 +16,7 @@
   -->
 
 <resources>
+    <string name="accessibility_shortcut_description_pref" translatable="false">shortcut_description</string>
     <string name="accessibility_shortcut_volume_keys_pref" translatable="false">shortcut_volume_keys_pref</string>
     <string name="accessibility_shortcut_gesture_pref" translatable="false">shortcut_gesture_pref</string>
     <string name="accessibility_shortcut_nav_button_pref" translatable="false">shortcut_nav_button_pref</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 45305ec..533c9b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5096,6 +5096,10 @@
     <string name="accessibility_shortcut_type_hardware">Hold volume keys</string>
     <!-- Summary for accessibility shortcut preference for magnification triple tap shortcut type. [CHAR LIMIT=NONE] -->
     <string name="accessibility_shortcut_type_triple_tap">Triple tap screen</string>
+    <!-- Generic title for editing the shortcuts of multiple accessibility features. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_screen_title">Edit accessibility shortcuts</string>
+    <!-- Prompt for editing the shortcuts of multiple accessibility features. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_screen_prompt">Chose your shortcut for %1$s</string>
 
     <!-- Button text for the accessibility dialog continue to the next screen for hearing aid. [CHAR LIMIT=32] -->
     <string name="accessibility_hearingaid_instruction_continue_button">Continue</string>
diff --git a/res/xml/accessibility_edit_shortcuts.xml b/res/xml/accessibility_edit_shortcuts.xml
index 06cbedd..8be0ee5 100644
--- a/res/xml/accessibility_edit_shortcuts.xml
+++ b/res/xml/accessibility_edit_shortcuts.xml
@@ -18,62 +18,66 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto">
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_fab_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.FloatingButtonShortcutOptionController" />
+    <PreferenceCategory
+        android:key="@string/accessibility_shortcut_description_pref">
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_gesture_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.GestureShortcutOptionController" />
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_fab_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.FloatingButtonShortcutOptionController" />
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_nav_button_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.NavButtonShortcutOptionController" />
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_gesture_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.GestureShortcutOptionController" />
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_volume_keys_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.VolumeKeysShortcutOptionController" />
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_nav_button_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.NavButtonShortcutOptionController" />
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_two_fingers_double_tap_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.TwoFingersDoubleTapShortcutOptionController" />
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_volume_keys_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.VolumeKeysShortcutOptionController" />
 
-    <Preference
-        android:icon="@drawable/ic_keyboard_arrow_down"
-        android:key="@string/accessibility_shortcuts_advanced_collapsed"
-        android:persistent="false"
-        android:selectable="true"
-        android:title="@string/accessibility_shortcut_edit_dialog_title_advance"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.AdvancedShortcutsPreferenceController" />
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_two_fingers_double_tap_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.TwoFingersDoubleTapShortcutOptionController" />
 
-    <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
-        android:key="@string/accessibility_shortcut_triple_tap_pref"
-        android:persistent="false"
-        android:selectable="true"
-        settings:allowDividerAbove="false"
-        settings:allowDividerBelow="false"
-        settings:controller="com.android.settings.accessibility.shortcuts.TripleTapShortcutOptionController" />
+        <Preference
+            android:icon="@drawable/ic_keyboard_arrow_down"
+            android:key="@string/accessibility_shortcuts_advanced_collapsed"
+            android:persistent="false"
+            android:selectable="true"
+            android:title="@string/accessibility_shortcut_edit_dialog_title_advance"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.AdvancedShortcutsPreferenceController" />
+
+        <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+            android:key="@string/accessibility_shortcut_triple_tap_pref"
+            android:persistent="false"
+            android:selectable="true"
+            settings:allowDividerAbove="false"
+            settings:allowDividerBelow="false"
+            settings:controller="com.android.settings.accessibility.shortcuts.TripleTapShortcutOptionController" />
+    </PreferenceCategory>
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
index a3cbb57..5a3b13a 100644
--- a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
@@ -27,16 +27,21 @@
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE;
 
+import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.icu.text.ListFormatter;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -48,9 +53,12 @@
 import androidx.preference.Preference;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.internal.accessibility.dialog.AccessibilityTargetHelper;
 import com.android.settings.R;
 import com.android.settings.SetupWizardUtils;
 import com.android.settings.accessibility.AccessibilitySetupWizardUtils;
+import com.android.settings.accessibility.Flags;
 import com.android.settings.accessibility.PreferredShortcuts;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.DashboardFragment;
@@ -60,7 +68,10 @@
 import com.google.android.setupcompat.util.WizardManagerHelper;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -171,6 +182,36 @@
         registerSettingsObserver();
     }
 
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        super.onCreatePreferences(savedInstanceState, rootKey);
+
+        Activity activity = getActivity();
+
+        if (!activity.getIntent().getAction().equals(
+                Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS)
+                || !Flags.editShortcutsInFullScreen()) {
+            return;
+        }
+
+        // TODO(b/325664350): Implement shortcut type for "all shortcuts"
+        List<AccessibilityTarget> accessibilityTargets =
+                AccessibilityTargetHelper.getInstalledTargets(
+                        activity.getBaseContext(), AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY);
+
+        Pair<String, String> titles = getTitlesFromAccessibilityTargetList(
+                mShortcutTargets,
+                accessibilityTargets,
+                activity.getResources()
+        );
+
+        activity.setTitle(titles.first);
+
+        String categoryKey = activity.getResources().getString(
+                R.string.accessibility_shortcut_description_pref);
+        findPreference(categoryKey).setTitle(titles.second);
+    }
+
     @NonNull
     @Override
     public RecyclerView onCreateRecyclerView(
@@ -275,7 +316,6 @@
         }
 
         mShortcutTargets = Set.of(targets);
-        // TODO(318748373): use 'targets' to populate title when no title is given
     }
 
     @Override
@@ -356,4 +396,52 @@
         // A11y Nav Button
         refreshPreferenceController(NavButtonShortcutOptionController.class);
     }
+
+    /**
+     * Generates a title & subtitle pair describing the features whose shortcuts are being edited.
+     *
+     * @param shortcutTargets string list of component names corresponding to
+     *                        the relevant shortcut targets.
+     * @param accessibilityTargets list of accessibility targets
+     *                             to try and find corresponding labels in.
+     * @return pair of strings to be used as page title and subtitle.
+     * If there is only one shortcut label, It is displayed in the title and the subtitle is null.
+     * Otherwise, the title is a generic prompt and the subtitle lists all shortcut labels.
+     */
+    @VisibleForTesting
+    static Pair<String, String> getTitlesFromAccessibilityTargetList(
+            Set<String> shortcutTargets,
+            List<AccessibilityTarget> accessibilityTargets,
+            Resources resources) {
+        ArrayList<CharSequence> featureLabels = new ArrayList<>();
+
+        Map<String, CharSequence> accessibilityTargetLabels = new ArrayMap<>();
+        accessibilityTargets.forEach((target) -> accessibilityTargetLabels.put(
+                target.getId(), target.getLabel()));
+
+        for (String target: shortcutTargets) {
+            if (accessibilityTargetLabels.containsKey(target)) {
+                featureLabels.add(accessibilityTargetLabels.get(target));
+            } else {
+                throw new IllegalStateException("Shortcut target does not have a label: " + target);
+            }
+        }
+
+        if (featureLabels.size() == 1) {
+            return new Pair<>(
+                    resources.getString(
+                            R.string.accessibility_shortcut_title, featureLabels.get(0)),
+                    null
+            );
+        } else if (featureLabels.size() == 0) {
+            throw new IllegalStateException("Found no labels for any shortcut targets.");
+        } else {
+            return new Pair<>(
+                    resources.getString(R.string.accessibility_shortcut_edit_screen_title),
+                    resources.getString(
+                            R.string.accessibility_shortcut_edit_screen_prompt,
+                            ListFormatter.getInstance().format(featureLabels))
+            );
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
index 13f0b24..b2ddb6c 100644
--- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
@@ -28,6 +28,9 @@
 import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.content.ComponentName;
@@ -35,7 +38,9 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
+import android.util.Pair;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.fragment.app.FragmentActivity;
@@ -46,6 +51,7 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.accessibility.util.ShortcutUtils;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -60,6 +66,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -89,6 +96,9 @@
     private static final String TARGET = MAGNIFICATION_CONTROLLER_NAME;
     private static final Set<String> TARGETS = Set.of(TARGET);
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private FragmentActivity mActivity;
     private FragmentScenario<EditShortcutsPreferenceFragment> mFragmentScenario;
@@ -414,6 +424,60 @@
 
     }
 
+    @Test
+    public void findTitles_withSingleTarget_hasNullSubtitle() {
+        final String fake_label = "FAKE";
+        List<AccessibilityTarget> accessibilityTargets = List.of(
+                generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
+
+        Pair<String, String> titles = EditShortcutsPreferenceFragment
+                .getTitlesFromAccessibilityTargetList(
+                        Set.of(TARGET_FAKE_COMPONENT.flattenToString()),
+                        accessibilityTargets, mActivity.getResources()
+                );
+
+        assertThat(titles.first).isNotNull();
+        assertThat(titles.first).contains(fake_label);
+        assertThat(titles.second).isNull();
+    }
+
+    @Test
+    public void findTitles_withMoreTargets_hasSubtitle() {
+        final String fake_label = "FAKE";
+        final String magnification_label = "MAGNIFICATION";
+        List<AccessibilityTarget> accessibilityTargets = List.of(
+                generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label),
+                generateAccessibilityTargetMock(MAGNIFICATION_COMPONENT_NAME, magnification_label));
+
+        Pair<String, String> titles = EditShortcutsPreferenceFragment
+                .getTitlesFromAccessibilityTargetList(
+                        Set.of(TARGET_FAKE_COMPONENT.flattenToString(),
+                                MAGNIFICATION_COMPONENT_NAME.flattenToString()),
+                        accessibilityTargets, mActivity.getResources()
+                );
+
+        assertThat(titles.first).isNotNull();
+        assertThat(titles.second).isNotNull();
+        assertThat(titles.second).contains(fake_label);
+        assertThat(titles.second).contains(magnification_label);
+    }
+
+    @Test
+    public void findTitles_targetMissing_labelNotInTitles() {
+        final String fake_label = "FAKE";
+        List<AccessibilityTarget> accessibilityTargets = List.of(
+                generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
+
+        assertThrows(IllegalStateException.class,
+                () -> EditShortcutsPreferenceFragment
+                        .getTitlesFromAccessibilityTargetList(
+                                Set.of(MAGNIFICATION_COMPONENT_NAME.flattenToString()),
+                                accessibilityTargets, mActivity.getResources()
+                        ));
+    }
+
+
+
     private void assertLaunchSubSettingWithCurrentTargetComponents(
             String componentName, boolean isInSuw) {
         Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity();
@@ -480,4 +544,12 @@
         intent.putExtra(EXTRA_IS_DEFERRED_SETUP, isInSuw);
         return intent;
     }
+
+    private AccessibilityTarget generateAccessibilityTargetMock(
+            ComponentName componentName, String label) {
+        AccessibilityTarget target = mock(AccessibilityTarget.class);
+        when(target.getComponentName()).thenReturn(componentName);
+        when(target.getLabel()).thenReturn(label);
+        return target;
+    }
 }