Expand SettingsLib ProviderTile to support non-switch type of Preferences

- Added new metadata allowing to set PendingIntent onto a Tile, which will be executed on click;
- Update the rendering logic to render with SwitchPreference only when Tile.hasSwitch() == true.

Test: robotest, manual
Bug: 281517110
Change-Id: I1253029be1e172792679f80be24bd58e368b9e73
This commit is contained in:
Peter Zhang
2023-05-07 23:55:50 +02:00
parent 860002b42c
commit ddb65e569b
6 changed files with 226 additions and 14 deletions

View File

@@ -33,6 +33,7 @@ import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWIT
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
@@ -75,6 +76,8 @@ import com.android.settingslib.drawer.TileUtils;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AdaptiveIcon;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -152,7 +155,14 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
bindIcon(pref, tile, forceRoundedIcon);
if (tile instanceof ActivityTile) {
if (tile.hasPendingIntent()) {
// Pending intent cannot be launched within the settings app panel, and will thus always
// be executed directly.
pref.setOnPreferenceClickListener(preference -> {
launchPendingIntentOrSelectProfile(activity, tile, fragment.getMetricsCategory());
return true;
});
} else if (tile instanceof ActivityTile) {
final int sourceMetricsCategory = fragment.getMetricsCategory();
final Bundle metadata = tile.getMetaData();
String clsName = null;
@@ -441,6 +451,33 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
preference.setIcon(iconDrawable);
}
private void launchPendingIntentOrSelectProfile(FragmentActivity activity, Tile tile,
int sourceMetricCategory) {
ProfileSelectDialog.updatePendingIntentsIfNeeded(mContext, tile);
if (tile.pendingIntentMap.isEmpty()) {
Log.w(TAG, "Cannot resolve pendingIntent, skipping. " + tile.getIntent());
return;
}
mMetricsFeatureProvider.logSettingsTileClick(tile.getKey(mContext), sourceMetricCategory);
// Launch the pending intent directly if there's only one available.
if (tile.pendingIntentMap.size() == 1) {
PendingIntent pendingIntent = Iterables.getOnlyElement(tile.pendingIntentMap.values());
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Failed executing pendingIntent. " + pendingIntent.getIntent(), e);
}
return;
}
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
sourceMetricCategory, /* onShowListener= */ null,
/* onDismissListener= */ null, /* onCancelListener= */ null);
}
private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
int sourceMetricCategory, TopLevelHighlightMixin highlightMixin,
boolean isDuplicateClick) {

View File

@@ -46,8 +46,8 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.drawer.ActivityTile;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProviderTile;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.search.Indexable;
@@ -569,11 +569,13 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
}
protected Preference createPreference(Tile tile) {
return tile instanceof ProviderTile
? new SwitchPreference(getPrefContext())
: tile.hasSwitch()
? new PrimarySwitchPreference(getPrefContext())
: new Preference(getPrefContext());
if (tile.hasSwitch()) {
return (tile instanceof ActivityTile || tile.hasPendingIntent())
? new PrimarySwitchPreference(getPrefContext())
: new SwitchPreference(getPrefContext());
} else {
return new Preference(getPrefContext());
}
}
@VisibleForTesting

View File

@@ -17,6 +17,7 @@
package com.android.settings.dashboard.profileselector;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -127,13 +128,25 @@ public class ProfileSelectDialog extends DialogFragment implements UserAdapter.O
@Override
public void onClick(int position) {
final UserHandle user = mSelectedTile.userHandle.get(position);
// Show menu on top level items.
final Intent intent = new Intent(mSelectedTile.getIntent());
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.logStartedIntentWithProfile(intent, mSourceMetricCategory,
position == 1 /* isWorkProfile */);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
getActivity().startActivityAsUser(intent, user);
if (!mSelectedTile.hasPendingIntent()) {
final Intent intent = new Intent(mSelectedTile.getIntent());
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.logStartedIntentWithProfile(intent, mSourceMetricCategory,
position == 1 /* isWorkProfile */);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
getActivity().startActivityAsUser(intent, user);
} else {
PendingIntent pendingIntent = mSelectedTile.pendingIntentMap.get(user);
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.logSettingsTileClickWithProfile(mSelectedTile.getKey(getContext()),
mSourceMetricCategory,
position == 1 /* isWorkProfile */);
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Failed executing pendingIntent. " + pendingIntent.getIntent(), e);
}
}
dismiss();
}
@@ -178,4 +191,36 @@ public class ProfileSelectDialog extends DialogFragment implements UserAdapter.O
}
}
}
/**
* Checks the userHandle and pendingIntentMap in the provided tile, and remove the invalid
* entries if any.
*/
public static void updatePendingIntentsIfNeeded(Context context, Tile tile) {
if (tile.userHandle == null || tile.userHandle.size() <= 1
|| tile.pendingIntentMap.size() <= 1) {
return;
}
for (UserHandle userHandle : List.copyOf(tile.userHandle)) {
if (!tile.pendingIntentMap.containsKey(userHandle)) {
if (DEBUG) {
Log.d(TAG, "Delete the user without pending intent: "
+ userHandle.getIdentifier());
}
tile.userHandle.remove(userHandle);
}
}
final UserManager userManager = UserManager.get(context);
for (UserHandle userHandle : List.copyOf(tile.pendingIntentMap.keySet())) {
UserInfo userInfo = userManager.getUserInfo(userHandle.getIdentifier());
if (userInfo == null || userInfo.isCloneProfile()) {
if (DEBUG) {
Log.d(TAG, "Delete the user: " + userHandle.getIdentifier());
}
tile.userHandle.remove(userHandle);
tile.pendingIntentMap.remove(userHandle);
}
}
}
}