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
This commit is contained in:
@@ -180,15 +180,17 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
|||||||
}
|
}
|
||||||
pref.setOnPreferenceClickListener(preference -> {
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
TopLevelHighlightMixin highlightMixin = null;
|
TopLevelHighlightMixin highlightMixin = null;
|
||||||
|
boolean isDuplicateClick = false;
|
||||||
if (fragment instanceof TopLevelSettings
|
if (fragment instanceof TopLevelSettings
|
||||||
&& ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
|
&& ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
|
||||||
// Highlight the preference whenever it's clicked
|
// Highlight the preference whenever it's clicked
|
||||||
final TopLevelSettings topLevelSettings = (TopLevelSettings) fragment;
|
final TopLevelSettings topLevelSettings = (TopLevelSettings) fragment;
|
||||||
topLevelSettings.setHighlightPreferenceKey(key);
|
topLevelSettings.setHighlightPreferenceKey(key);
|
||||||
highlightMixin = topLevelSettings.getHighlightMixin();
|
highlightMixin = topLevelSettings.getHighlightMixin();
|
||||||
|
isDuplicateClick = topLevelSettings.isDuplicateClick(preference);
|
||||||
}
|
}
|
||||||
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory,
|
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory,
|
||||||
highlightMixin);
|
highlightMixin, isDuplicateClick);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -221,7 +223,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
|||||||
SettingsEnums.DASHBOARD_SUMMARY)
|
SettingsEnums.DASHBOARD_SUMMARY)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY,
|
launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY,
|
||||||
/* highlightMixin= */ null);
|
/* highlightMixin= */ null, /* isDuplicateClick= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
|
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,
|
private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
|
||||||
int sourceMetricCategory, TopLevelHighlightMixin highlightMixin) {
|
int sourceMetricCategory, TopLevelHighlightMixin highlightMixin,
|
||||||
|
boolean isDuplicateClick) {
|
||||||
if (!isIntentResolvable(intent)) {
|
if (!isIntentResolvable(intent)) {
|
||||||
Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
|
Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
|
ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
|
||||||
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
|
||||||
|
|
||||||
if (tile.userHandle == null || tile.isPrimaryProfileOnly()) {
|
if (tile.userHandle == null || tile.isPrimaryProfileOnly()) {
|
||||||
|
if (!isDuplicateClick) {
|
||||||
|
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
|
}
|
||||||
} else if (tile.userHandle.size() == 1) {
|
} else if (tile.userHandle.size() == 1) {
|
||||||
|
if (!isDuplicateClick) {
|
||||||
|
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
||||||
activity.startActivityAsUser(intent, tile.userHandle.get(0));
|
activity.startActivityAsUser(intent, tile.userHandle.get(0));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER);
|
final UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER);
|
||||||
if (userHandle != null && tile.userHandle.contains(userHandle)) {
|
if (userHandle != null && tile.userHandle.contains(userHandle)) {
|
||||||
|
if (!isDuplicateClick) {
|
||||||
|
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
||||||
activity.startActivityAsUser(intent, userHandle);
|
activity.startActivityAsUser(intent, userHandle);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<UserHandle> resolvableUsers = getResolvableUsers(intent, tile);
|
final List<UserHandle> resolvableUsers = getResolvableUsers(intent, tile);
|
||||||
if (resolvableUsers.size() == 1) {
|
if (resolvableUsers.size() == 1) {
|
||||||
|
if (!isDuplicateClick) {
|
||||||
|
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
||||||
activity.startActivityAsUser(intent, resolvableUsers.get(0));
|
activity.startActivityAsUser(intent, resolvableUsers.get(0));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show the profile select dialog regardless of the duplicate click.
|
||||||
|
mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
|
||||||
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
|
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
|
||||||
sourceMetricCategory, /* onShowListener= */ highlightMixin,
|
sourceMetricCategory, /* onShowListener= */ highlightMixin,
|
||||||
/* onDismissListener= */ highlightMixin,
|
/* onDismissListener= */ highlightMixin,
|
||||||
|
@@ -140,6 +140,10 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getHighlightPreferenceKey() {
|
||||||
|
return mCurrentKey;
|
||||||
|
}
|
||||||
|
|
||||||
void highlightPreferenceIfNeeded() {
|
void highlightPreferenceIfNeeded() {
|
||||||
if (mTopLevelAdapter != null) {
|
if (mTopLevelAdapter != null) {
|
||||||
mTopLevelAdapter.requestHighlight();
|
mTopLevelAdapter.requestHighlight();
|
||||||
|
@@ -16,12 +16,17 @@
|
|||||||
|
|
||||||
package com.android.settings.homepage;
|
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.settings.search.actionbar.SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR;
|
||||||
import static com.android.settingslib.search.SearchIndexable.MOBILE;
|
import static com.android.settingslib.search.SearchIndexable.MOBILE;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
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.content.res.Configuration;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -38,6 +43,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import androidx.window.embedding.SplitController;
|
import androidx.window.embedding.SplitController;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
||||||
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
|
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.drawer.Tile;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
@SearchIndexable(forTarget = MOBILE)
|
@SearchIndexable(forTarget = MOBILE)
|
||||||
public class TopLevelSettings extends DashboardFragment implements SplitLayoutListener,
|
public class TopLevelSettings extends DashboardFragment implements SplitLayoutListener,
|
||||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||||
|
|
||||||
private static final String TAG = "TopLevelSettings";
|
private static final String TAG = "TopLevelSettings";
|
||||||
private static final String SAVED_HIGHLIGHT_MIXIN = "highlight_mixin";
|
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 static final String PREF_KEY_SUPPORT = "top_level_support";
|
||||||
|
|
||||||
private boolean mIsEmbeddingActivityEnabled;
|
private boolean mIsEmbeddingActivityEnabled;
|
||||||
@@ -64,6 +73,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
|
|||||||
private int mPaddingHorizontal;
|
private int mPaddingHorizontal;
|
||||||
private boolean mScrollNeeded = true;
|
private boolean mScrollNeeded = true;
|
||||||
private boolean mFirstStarted = true;
|
private boolean mFirstStarted = true;
|
||||||
|
private boolean mFirstDuplicateClickCheck = true;
|
||||||
|
|
||||||
public TopLevelSettings() {
|
public TopLevelSettings() {
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
@@ -107,6 +117,10 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
|
if (isDuplicateClick(preference)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Register SplitPairRule for SubSettings.
|
// Register SplitPairRule for SubSettings.
|
||||||
ActivityEmbeddingRulesController.registerSubSettingsPairRule(getContext(),
|
ActivityEmbeddingRulesController.registerSubSettingsPairRule(getContext(),
|
||||||
true /* clearTop */);
|
true /* clearTop */);
|
||||||
@@ -140,6 +154,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
|
|||||||
|
|
||||||
boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity());
|
boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity());
|
||||||
if (icicle != null) {
|
if (icicle != null) {
|
||||||
|
mFirstDuplicateClickCheck = icicle.getBoolean(SAVED_FIRST_PREFERENCE_CLICK);
|
||||||
mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
|
mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
|
||||||
mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded;
|
mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded;
|
||||||
mHighlightMixin.setActivityEmbedded(activityEmbedded);
|
mHighlightMixin.setActivityEmbedded(activityEmbedded);
|
||||||
@@ -173,6 +188,7 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putBoolean(SAVED_FIRST_PREFERENCE_CLICK, mFirstDuplicateClickCheck);
|
||||||
if (mHighlightMixin != null) {
|
if (mHighlightMixin != null) {
|
||||||
outState.putParcelable(SAVED_HIGHLIGHT_MIXIN, mHighlightMixin);
|
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 */
|
/** Show/hide the highlight on the menu entry for the search page presence */
|
||||||
public void setMenuHighlightShowed(boolean show) {
|
public void setMenuHighlightShowed(boolean show) {
|
||||||
if (mHighlightMixin != null) {
|
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) {
|
private void iteratePreferences(PreferenceJob job) {
|
||||||
if (job == null || getPreferenceManager() == null) {
|
if (job == null || getPreferenceManager() == null) {
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user