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

Commit 86458a95 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Handle duplicate backlinks in app clips" into main

parents 578e8b35 61a626cf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@
    <!-- Add to note button used in App Clips flow to return the saved screenshot image to notes app. [CHAR LIMIT=NONE] -->
    <string name="app_clips_save_add_to_note">Add to note</string>
    <string name="backlinks_include_link">Include link</string>
    <string name="backlinks_duplicate_label_format"><xliff:g id="appName" example="Google Chrome">%1$s</xliff:g> <xliff:g id="frequencyCount" example="(1)">(%2$d)</xliff:g></string>

    <!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
    <string name="screenrecord_title">Screen Recorder</string>
+58 −3
Original line number Diff line number Diff line
@@ -71,7 +71,9 @@ import com.android.systemui.res.R;
import com.android.systemui.screenshot.scroll.CropView;
import com.android.systemui.settings.UserTracker;

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

import javax.inject.Inject;
@@ -344,10 +346,63 @@ public class AppClipsActivity extends ComponentActivity {

        // Set up the dropdown when multiple backlinks are available.
        if (backlinksData.size() > 1) {
            setUpListPopupWindow(backlinksData, mBacklinksDataTextView);
            setUpListPopupWindow(updateBacklinkLabelsWithDuplicateNames(backlinksData),
                    mBacklinksDataTextView);
        }
    }

    /**
     * If there are more than 1 backlinks that have the same app name, then this method appends
     * a numerical suffix to such backlinks to help users distinguish.
     */
    private List<InternalBacklinksData> updateBacklinkLabelsWithDuplicateNames(
            List<InternalBacklinksData> backlinksData) {
        // Check if there are multiple backlinks with same name.
        Map<String, Integer> duplicateNamedBacklinksCountMap = new HashMap<>();
        for (InternalBacklinksData data : backlinksData) {
            if (duplicateNamedBacklinksCountMap.containsKey(data.getDisplayLabel())) {
                int duplicateCount = duplicateNamedBacklinksCountMap.get(data.getDisplayLabel());
                if (duplicateCount == 0) {
                    // If this is the first time the loop is coming across a duplicate name, set the
                    // count to 2. This way the count starts from 1 for all duplicate named
                    // backlinks.
                    duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), 2);
                } else {
                    // For all duplicate named backlinks, increase the duplicate count by 1.
                    duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), duplicateCount + 1);
                }
            } else {
                // This is the first time the loop is coming across a backlink with this name. Set
                // its count to 0. The loop will increase its count by 1 when a duplicate is found.
                duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), 0);
            }
        }

        // Go through the backlinks in reverse order as it is easier to assign the numerical suffix
        // in descending order of frequency using the duplicate map that was built earlier. For
        // example, if "App A" is present 3 times, then we assign display label "App A (3)" first
        // and then "App A (2)", lastly "App A (1)".
        for (InternalBacklinksData data : backlinksData.reversed()) {
            String originalBacklinkLabel = data.getDisplayLabel();
            int duplicateCount = duplicateNamedBacklinksCountMap.get(originalBacklinkLabel);

            // The display label should only be updated if there are multiple backlinks with the
            // same name.
            if (duplicateCount > 0) {
                // Update the display label to: "App name (count)"
                data.setDisplayLabel(
                        getString(R.string.backlinks_duplicate_label_format, originalBacklinkLabel,
                                duplicateCount));

                // Decrease the duplicate count and update the map.
                duplicateCount--;
                duplicateNamedBacklinksCountMap.put(originalBacklinkLabel, duplicateCount);
            }
        }

        return backlinksData;
    }

    private void setUpListPopupWindow(List<InternalBacklinksData> backlinksData, View anchor) {
        ListPopupWindow listPopupWindow = new ListPopupWindow(this);
        listPopupWindow.setAnchorView(anchor);
@@ -365,7 +420,7 @@ public class AppClipsActivity extends ComponentActivity {
            public View getView(int position, @Nullable View convertView, ViewGroup parent) {
                TextView itemView = (TextView) super.getView(position, convertView, parent);
                InternalBacklinksData data = backlinksData.get(position);
                itemView.setText(data.getClipData().getDescription().getLabel());
                itemView.setText(data.getDisplayLabel());

                Drawable icon = data.getAppIcon();
                icon.setBounds(createBacklinksTextViewDrawableBounds());
@@ -387,7 +442,7 @@ public class AppClipsActivity extends ComponentActivity {
     * expected to be already set when this method is called.
     */
    private void updateBacklinksTextView(InternalBacklinksData backlinksData) {
        mBacklinksDataTextView.setText(backlinksData.getClipData().getDescription().getLabel());
        mBacklinksDataTextView.setText(backlinksData.getDisplayLabel());
        Drawable appIcon = backlinksData.getAppIcon();
        Rect compoundDrawableBounds = createBacklinksTextViewDrawableBounds();
        appIcon.setBounds(compoundDrawableBounds);
+3 −1
Original line number Diff line number Diff line
@@ -20,4 +20,6 @@ import android.content.ClipData
import android.graphics.drawable.Drawable

/** A class to hold the [ClipData] for backlinks and the corresponding app's [Drawable] icon. */
internal data class InternalBacklinksData(val clipData: ClipData, val appIcon: Drawable)
internal data class InternalBacklinksData(val clipData: ClipData, val appIcon: Drawable) {
    var displayLabel: String = clipData.description.label.toString()
}
+34 −0
Original line number Diff line number Diff line
@@ -308,6 +308,40 @@ public final class AppClipsActivityTest extends SysuiTestCase {
        assertThat(backlinksData.getCompoundDrawablesRelative()[2]).isNotNull();
    }

    @Test
    @EnableFlags(Flags.FLAG_APP_CLIPS_BACKLINKS)
    public void appClipsLaunched_backlinks_multipleBacklinksAvailable_duplicateName()
            throws RemoteException {
        // Set up mocking for multiple backlinks.
        ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();

        ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
        RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
        int taskId2 = BACKLINKS_TASK_ID + 2;
        runningTaskInfo2.taskId = taskId2;

        when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
                mDisplayIdCaptor.capture()))
                .thenReturn(List.of(TASK_THAT_SUPPORTS_BACKLINKS, runningTaskInfo2));
        when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(resolveInfo1,
                resolveInfo1, resolveInfo1, resolveInfo2, resolveInfo2, resolveInfo2);
        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);

        // Using same AssistContent data for both tasks.
        mockForAssistContent(ASSIST_CONTENT_FOR_BACKLINKS_TASK, BACKLINKS_TASK_ID);
        mockForAssistContent(ASSIST_CONTENT_FOR_BACKLINKS_TASK, taskId2);

        // Mocking complete, trigger backlinks.
        launchActivity();
        waitForIdleSync();

        // Verify default backlink shown to user has the numerical suffix.
        TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
        assertThat(backlinksData.getText().toString()).isEqualTo(
                mContext.getString(R.string.backlinks_duplicate_label_format,
                        BACKLINKS_TASK_APP_NAME, 1));
    }

    private void setUpMocksForBacklinks() throws RemoteException {
        when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
                mDisplayIdCaptor.capture()))