Support highlightable Settings homepage menu for 2-pane

1. Add a preference group adapter to perform highlighting
2. Add a class for mapping highlighable menu keys and preference keys
3. Add an API to determine if the screen is in split mode

Bug: 199017944
Test: manual, build
Change-Id: I8e3fe5fb96480a31ee0f3b3afb6ad78999d3d2bc
This commit is contained in:
Jason Chiu
2021-09-09 16:54:01 +08:00
parent 02b3384ae1
commit 9037ceabd3
18 changed files with 775 additions and 91 deletions

View File

@@ -17,6 +17,7 @@ package com.android.settings.dashboard;
import android.content.ComponentName;
import android.content.Context;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -24,6 +25,7 @@ import android.util.Pair;
import androidx.annotation.VisibleForTesting;
import com.android.settings.homepage.HighlightableMenu;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
@@ -153,6 +155,14 @@ public class CategoryManager {
filterDuplicateTiles(mCategoryByKeyMap);
if (firstLoading) {
logTiles(context);
for (Tile tile : mCategoryByKeyMap.get(CategoryKey.CATEGORY_HOMEPAGE).getTiles()) {
final String key = tile.getKey(context);
if (TextUtils.isEmpty(key)) {
Log.w(TAG, "Key hint missing for homepage tile: " + tile.getTitle(context));
continue;
}
HighlightableMenu.addMenuKey(key);
}
}
}
}

View File

@@ -47,9 +47,9 @@ public interface DashboardFeatureProvider {
* Binds preference to data provided by tile and gets dynamic data observers.
*
* @param activity If tile contains intent to launch, it will be launched from this activity
* @param fragment The fragment that the preference will be bound to
* @param forceRoundedIcon Whether or not injected tiles from other packages should be forced to
* rounded icon.
* @param sourceMetricsCategory The context (source) from which an action is performed
* @param pref The preference to bind data
* @param tile The binding data
* @param key They key for preference. If null, we will generate one from tile data
@@ -58,7 +58,7 @@ public interface DashboardFeatureProvider {
* @return The list of dynamic data observers
*/
List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
DashboardFragment fragment, boolean forceRoundedIcon, Preference pref, Tile tile,
String key, int baseOrder);
/**

View File

@@ -36,6 +36,7 @@ import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITL
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface.OnCancelListener;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -60,6 +61,7 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.PrimarySwitchPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -123,7 +125,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
@Override
public List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
DashboardFragment fragment, boolean forceRoundedIcon, Preference pref, Tile tile,
String key, int baseOrder) {
if (pref == null) {
return null;
@@ -149,6 +151,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
bindIcon(pref, tile, forceRoundedIcon);
if (tile instanceof ActivityTile) {
final int sourceMetricsCategory = fragment.getMetricsCategory();
final Bundle metadata = tile.getMetaData();
String clsName = null;
String action = null;
@@ -166,7 +169,17 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
intent.setAction(action);
}
pref.setOnPreferenceClickListener(preference -> {
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory);
OnCancelListener listener = null;
if (fragment instanceof TopLevelSettings) {
final TopLevelSettings topLevelSettings = (TopLevelSettings) fragment;
// Highlight the tile immediately whenever it's clicked
topLevelSettings.setHighlightPreferenceKey(key);
// If the tile allows users to select profile, the pop-op dialog may be
// cancelled and then the previous highlight entry should be restored.
listener = dialog -> topLevelSettings.restorePreviousHighlight();
}
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory,
listener);
return true;
});
}
@@ -198,7 +211,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.DASHBOARD_SUMMARY)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY);
launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY,
/* listener= */ null);
}
private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
@@ -413,7 +427,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
int sourceMetricCategory) {
int sourceMetricCategory, OnCancelListener listener) {
if (!isIntentResolvable(intent)) {
Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
return;
@@ -439,7 +453,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
sourceMetricCategory);
sourceMetricCategory, listener);
}
}

View File

@@ -496,15 +496,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
if (mDashboardTilePrefKeys.containsKey(key)) {
// Have the key already, will rebind.
final Preference preference = screen.findPreference(key);
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
forceRoundedIcons, getMetricsCategory(), preference, tile, key,
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(), this,
forceRoundedIcons, preference, tile, key,
mPlaceholderPreferenceController.getOrder());
} else {
// Don't have this key, add it.
final Preference pref = createPreference(tile);
final List<DynamicDataObserver> observers =
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
forceRoundedIcons, getMetricsCategory(), pref, tile, key,
this, forceRoundedIcons, pref, tile, key,
mPlaceholderPreferenceController.getOrder());
screen.addPreference(pref);
registerDynamicDataObservers(observers);

View File

@@ -19,6 +19,7 @@ package com.android.settings.dashboard.profileselector;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
@@ -44,19 +45,23 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen
private int mSourceMetricCategory;
private Tile mSelectedTile;
private OnCancelListener mOnCancelListener;
/**
* Display the profile select dialog, adding the fragment to the given FragmentManager.
* @param manager The FragmentManager this fragment will be added to.
* @param tile The tile for this fragment.
* @param sourceMetricCategory The source metric category.
* @param listener The listener listens to the dialog cancelling event.
*/
public static void show(FragmentManager manager, Tile tile, int sourceMetricCategory) {
public static void show(FragmentManager manager, Tile tile, int sourceMetricCategory,
OnCancelListener listener) {
final ProfileSelectDialog dialog = new ProfileSelectDialog();
final Bundle args = new Bundle();
args.putParcelable(ARG_SELECTED_TILE, tile);
args.putInt(ARG_SOURCE_METRIC_CATEGORY, sourceMetricCategory);
dialog.setArguments(args);
dialog.mOnCancelListener = listener;
dialog.show(manager, "select_profile");
}
@@ -91,6 +96,13 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen
getActivity().startActivityAsUser(intent, user);
}
@Override
public void onCancel(DialogInterface dialog) {
if (mOnCancelListener != null) {
mOnCancelListener.onCancel(dialog);
}
}
public static void updateUserHandlesIfNeeded(Context context, Tile tile) {
final List<UserHandle> userHandles = tile.userHandle;
if (tile.userHandle == null || tile.userHandle.size() <= 1) {