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

Commit e04dfaa2 authored by Jason Chiu's avatar Jason Chiu
Browse files

Filter out the duplicate click event on menu page

Whenever the highlighted item is clicked, Settings shouldn't start the
second-layer page again even if the user goes to its child page.
Ex. When the user goes to the Tethering page, clicking on the menu
entry "Network & Internet" should not switch to the page.

Exception: in the deep link case, allow the first click event on the
highlighted item to launch the second-layer page when the page is not
the same as the one on the right pane.

Fix: 215267159
Test: manual, robotest
Change-Id: I2315e0069facc4867cb157752b1a3144716b7d17
parent c4899bf0
Loading
Loading
Loading
Loading
+24 −8
Original line number Diff line number Diff line
@@ -180,15 +180,17 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
                }
                pref.setOnPreferenceClickListener(preference -> {
                    TopLevelHighlightMixin highlightMixin = null;
                    boolean isDuplicateClick = false;
                    if (fragment instanceof TopLevelSettings
                            && ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
                        // Highlight the preference whenever it's clicked
                        final TopLevelSettings topLevelSettings = (TopLevelSettings) fragment;
                        topLevelSettings.setHighlightPreferenceKey(key);
                        highlightMixin = topLevelSettings.getHighlightMixin();
                        isDuplicateClick = topLevelSettings.isDuplicateClick(preference);
                    }
                    launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory,
                            highlightMixin);
                            highlightMixin, isDuplicateClick);
                    return true;
                });
            }
@@ -221,7 +223,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
                        SettingsEnums.DASHBOARD_SUMMARY)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY,
                /* highlightMixin= */ null);
                /* highlightMixin= */ null, /* isDuplicateClick= */ false);
    }

    private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
@@ -433,31 +435,45 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
    }

    private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
            int sourceMetricCategory, TopLevelHighlightMixin highlightMixin) {
            int sourceMetricCategory, TopLevelHighlightMixin highlightMixin,
            boolean isDuplicateClick) {
        if (!isIntentResolvable(intent)) {
            Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
            return;
        }
        ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
        mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);

        if (tile.userHandle == null || tile.isPrimaryProfileOnly()) {
            if (!isDuplicateClick) {
                mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
                activity.startActivity(intent);
            }
        } else if (tile.userHandle.size() == 1) {
            if (!isDuplicateClick) {
                mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
                activity.startActivityAsUser(intent, tile.userHandle.get(0));
            }
        } else {
            final UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER);
            if (userHandle != null && tile.userHandle.contains(userHandle)) {
                if (!isDuplicateClick) {
                    mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
                    activity.startActivityAsUser(intent, userHandle);
                }
                return;
            }

            final List<UserHandle> resolvableUsers = getResolvableUsers(intent, tile);
            if (resolvableUsers.size() == 1) {
                if (!isDuplicateClick) {
                    mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
                    activity.startActivityAsUser(intent, resolvableUsers.get(0));
                }
                return;
            }

            // Show the profile select dialog regardless of the duplicate click.
            mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
            ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
                    sourceMetricCategory, /* onShowListener= */ highlightMixin,
                    /* onDismissListener= */ highlightMixin,
+4 −0
Original line number Diff line number Diff line
@@ -140,6 +140,10 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
        }
    }

    String getHighlightPreferenceKey() {
        return mCurrentKey;
    }

    void highlightPreferenceIfNeeded() {
        if (mTopLevelAdapter != null) {
            mTopLevelAdapter.requestHighlight();
+72 −0
Original line number Diff line number Diff line
@@ -16,12 +16,17 @@

package com.android.settings.homepage;

import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;

import static com.android.settings.search.actionbar.SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR;
import static com.android.settingslib.search.SearchIndexable.MOBILE;

import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -38,6 +43,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.window.embedding.SplitController;

import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
@@ -51,12 +57,15 @@ import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.search.SearchIndexable;

import java.net.URISyntaxException;

@SearchIndexable(forTarget = MOBILE)
public class TopLevelSettings extends DashboardFragment implements SplitLayoutListener,
        PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {

    private static final String TAG = "TopLevelSettings";
    private static final String SAVED_HIGHLIGHT_MIXIN = "highlight_mixin";
    private static final String SAVED_FIRST_PREFERENCE_CLICK = "first_pref_click";
    private static final String PREF_KEY_SUPPORT = "top_level_support";

    private boolean mIsEmbeddingActivityEnabled;
@@ -64,6 +73,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
    private int mPaddingHorizontal;
    private boolean mScrollNeeded = true;
    private boolean mFirstStarted = true;
    private boolean mFirstDuplicateClickCheck = true;

    public TopLevelSettings() {
        final Bundle args = new Bundle();
@@ -107,6 +117,10 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (isDuplicateClick(preference)) {
            return true;
        }

        // Register SplitPairRule for SubSettings.
        ActivityEmbeddingRulesController.registerSubSettingsPairRule(getContext(),
                true /* clearTop */);
@@ -140,6 +154,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi

        boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity());
        if (icicle != null) {
            mFirstDuplicateClickCheck = icicle.getBoolean(SAVED_FIRST_PREFERENCE_CLICK);
            mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
            mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded;
            mHighlightMixin.setActivityEmbedded(activityEmbedded);
@@ -173,6 +188,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(SAVED_FIRST_PREFERENCE_CLICK, mFirstDuplicateClickCheck);
        if (mHighlightMixin != null) {
            outState.putParcelable(SAVED_HIGHLIGHT_MIXIN, mHighlightMixin);
        }
@@ -271,6 +287,41 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
        }
    }

    /** Returns whether clicking the specified preference is considered as a duplicate click. */
    public boolean isDuplicateClick(Preference pref) {
        boolean firstCheck = mFirstDuplicateClickCheck;
        mFirstDuplicateClickCheck = false;
        /*
         * Return false when
         * 1. The device doesn't support activity embedding
         * 2. The target preference is not highlighted
         * 3. The current activity is not embedded
         */
        if (mHighlightMixin == null
                || !TextUtils.equals(pref.getKey(), mHighlightMixin.getHighlightPreferenceKey())
                || !SplitController.getInstance().isActivityEmbedded(getActivity())) {
            return false;
        }

        /*
         * Return true when
         * 1. This method has been called before
         * 2. The preference doesn't have a target fragment, ex. Wallpaper and injections
         */
        if (!firstCheck || TextUtils.isEmpty(pref.getFragment())) {
            return true;
        }

        /*
         * Returns true when
         * 1. The right pane fragment is not started by a deep link.
         * 2. The target fragment equals the right pane fragment
         */
        String intentUri = getIntent().getStringExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI);
        return TextUtils.isEmpty(intentUri)
                || TextUtils.equals(pref.getFragment(), getIntentTargetFragment(intentUri));
    }

    /** Show/hide the highlight on the menu entry for the search page presence */
    public void setMenuHighlightShowed(boolean show) {
        if (mHighlightMixin != null) {
@@ -310,6 +361,27 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
        }
    }

    private String getIntentTargetFragment(String intentUri) {
        Intent targetIntent;
        try {
            targetIntent = Intent.parseUri(intentUri, Intent.URI_INTENT_SCHEME);
        } catch (URISyntaxException e) {
            return null;
        }

        String fragment = targetIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT);
        if (!TextUtils.isEmpty(fragment)) {
            return fragment;
        }

        ActivityInfo info = targetIntent.resolveActivityInfo(getPackageManager(),
                PackageManager.GET_META_DATA);
        if (info == null || info.metaData == null) {
            return null;
        }
        return info.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
    }

    private void iteratePreferences(PreferenceJob job) {
        if (job == null || getPreferenceManager() == null) {
            return;