[Settings] Support pure switch of inline toggle of Settings Injection v2
Bug: 132808482 Test: robotest Change-Id: Ib24614fb46fe990925edad721e3b7d5d032854fc
This commit is contained in:
@@ -27,6 +27,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
import com.android.settingslib.applications.InterestingConfigChanges;
|
||||
import com.android.settingslib.drawer.CategoryKey;
|
||||
import com.android.settingslib.drawer.DashboardCategory;
|
||||
import com.android.settingslib.drawer.ProviderTile;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
import com.android.settingslib.drawer.TileUtils;
|
||||
|
||||
@@ -189,21 +190,31 @@ public class CategoryManager {
|
||||
|
||||
/**
|
||||
* Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the
|
||||
* same intent.
|
||||
* same intent for ActivityTile, and also the ones having the same description for ProviderTile.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
|
||||
for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
|
||||
final DashboardCategory category = categoryEntry.getValue();
|
||||
final int count = category.getTilesCount();
|
||||
final Set<String> descriptions = new ArraySet<>();
|
||||
final Set<ComponentName> components = new ArraySet<>();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
final Tile tile = category.getTile(i);
|
||||
final ComponentName tileComponent = tile.getIntent().getComponent();
|
||||
if (components.contains(tileComponent)) {
|
||||
category.removeTile(i);
|
||||
if (tile instanceof ProviderTile) {
|
||||
final String desc = tile.getDescription();
|
||||
if (descriptions.contains(desc)) {
|
||||
category.removeTile(i);
|
||||
} else {
|
||||
descriptions.add(desc);
|
||||
}
|
||||
} else {
|
||||
components.add(tileComponent);
|
||||
final ComponentName tileComponent = tile.getIntent().getComponent();
|
||||
if (components.contains(tileComponent)) {
|
||||
category.removeTile(i);
|
||||
} else {
|
||||
components.add(tileComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -44,19 +44,22 @@ public interface DashboardFeatureProvider {
|
||||
String getDashboardKeyForTile(Tile tile);
|
||||
|
||||
/**
|
||||
* Binds preference to data provided by tile.
|
||||
* 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 forceRoundedIcon Whether or not injected tiles from other packages should be forced to rounded icon.
|
||||
* @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
|
||||
* @param baseOrder The order offset value. When binding, pref's order is determined by
|
||||
* both this value and tile's own priority.
|
||||
* @return The list of dynamic data observers
|
||||
*/
|
||||
void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon,
|
||||
int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder);
|
||||
List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
|
||||
boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
|
||||
String key, int baseOrder);
|
||||
|
||||
/**
|
||||
* Opens a tile to its destination intent.
|
||||
|
@@ -18,9 +18,18 @@ package com.android.settings.dashboard;
|
||||
|
||||
import static android.content.Intent.EXTRA_USER;
|
||||
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_CHECKED_STATE;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_TITLE;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_PROVIDER_ICON;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.METHOD_IS_CHECKED;
|
||||
import static com.android.settingslib.drawer.SwitchesProvider.METHOD_ON_CHECKED_CHANGED;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
|
||||
|
||||
@@ -40,22 +49,26 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.drawer.ActivityTile;
|
||||
import com.android.settingslib.drawer.DashboardCategory;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
import com.android.settingslib.drawer.TileUtils;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.settingslib.widget.AdaptiveIcon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -106,40 +119,54 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon,
|
||||
int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder) {
|
||||
public List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
|
||||
boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
|
||||
String key, int baseOrder) {
|
||||
if (pref == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (!TextUtils.isEmpty(key)) {
|
||||
pref.setKey(key);
|
||||
} else {
|
||||
pref.setKey(getDashboardKeyForTile(tile));
|
||||
}
|
||||
bindTitle(pref, tile);
|
||||
bindSummary(pref, tile);
|
||||
final List<DynamicDataObserver> outObservers = new ArrayList<>();
|
||||
DynamicDataObserver observer = bindTitleAndGetObserver(pref, tile);
|
||||
if (observer != null) {
|
||||
outObservers.add(observer);
|
||||
}
|
||||
observer = bindSummaryAndGetObserver(pref, tile);
|
||||
if (observer != null) {
|
||||
outObservers.add(observer);
|
||||
}
|
||||
observer = bindSwitchAndGetObserver(pref, tile);
|
||||
if (observer != null) {
|
||||
outObservers.add(observer);
|
||||
}
|
||||
bindIcon(pref, tile, forceRoundedIcon);
|
||||
|
||||
final Bundle metadata = tile.getMetaData();
|
||||
String clsName = null;
|
||||
String action = null;
|
||||
if (metadata != null) {
|
||||
clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
|
||||
action = metadata.getString(META_DATA_KEY_INTENT_ACTION);
|
||||
}
|
||||
if (!TextUtils.isEmpty(clsName)) {
|
||||
pref.setFragment(clsName);
|
||||
} else {
|
||||
final Intent intent = new Intent(tile.getIntent());
|
||||
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
|
||||
sourceMetricsCategory);
|
||||
if (action != null) {
|
||||
intent.setAction(action);
|
||||
if (tile instanceof ActivityTile) {
|
||||
final Bundle metadata = tile.getMetaData();
|
||||
String clsName = null;
|
||||
String action = null;
|
||||
if (metadata != null) {
|
||||
clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
|
||||
action = metadata.getString(META_DATA_KEY_INTENT_ACTION);
|
||||
}
|
||||
if (!TextUtils.isEmpty(clsName)) {
|
||||
pref.setFragment(clsName);
|
||||
} else {
|
||||
final Intent intent = new Intent(tile.getIntent());
|
||||
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
|
||||
sourceMetricsCategory);
|
||||
if (action != null) {
|
||||
intent.setAction(action);
|
||||
}
|
||||
pref.setOnPreferenceClickListener(preference -> {
|
||||
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
pref.setOnPreferenceClickListener(preference -> {
|
||||
launchIntentOrSelectProfile(activity, tile, intent, sourceMetricsCategory);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (tile.hasOrder()) {
|
||||
@@ -153,6 +180,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
pref.setOrder(order + baseOrder);
|
||||
}
|
||||
}
|
||||
return outObservers.isEmpty() ? null : outObservers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,11 +198,35 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
launchIntentOrSelectProfile(activity, tile, intent, SettingsEnums.DASHBOARD_SUMMARY);
|
||||
}
|
||||
|
||||
private void bindTitle(Preference preference, Tile tile) {
|
||||
private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
|
||||
return new DynamicDataObserver() {
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged() {
|
||||
switch (method) {
|
||||
case METHOD_GET_DYNAMIC_TITLE:
|
||||
refreshTitle(uri, pref);
|
||||
break;
|
||||
case METHOD_GET_DYNAMIC_SUMMARY:
|
||||
refreshSummary(uri, pref);
|
||||
break;
|
||||
case METHOD_IS_CHECKED:
|
||||
refreshSwitch(uri, pref);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private DynamicDataObserver bindTitleAndGetObserver(Preference preference, Tile tile) {
|
||||
final CharSequence title = tile.getTitle(mContext.getApplicationContext());
|
||||
if (title != null) {
|
||||
preference.setTitle(title);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (tile.getMetaData() != null && tile.getMetaData().containsKey(
|
||||
META_DATA_PREFERENCE_TITLE_URI)) {
|
||||
@@ -182,9 +234,12 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
// to avoid preference height change.
|
||||
preference.setTitle(R.string.summary_placeholder);
|
||||
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_TITLE_URI);
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_TITLE_URI,
|
||||
METHOD_GET_DYNAMIC_TITLE);
|
||||
refreshTitle(uri, preference);
|
||||
return createDynamicDataObserver(METHOD_GET_DYNAMIC_TITLE, uri, preference);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void refreshTitle(Uri uri, Preference preference) {
|
||||
@@ -196,7 +251,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private void bindSummary(Preference preference, Tile tile) {
|
||||
private DynamicDataObserver bindSummaryAndGetObserver(Preference preference, Tile tile) {
|
||||
final CharSequence summary = tile.getSummary(mContext);
|
||||
if (summary != null) {
|
||||
preference.setSummary(summary);
|
||||
@@ -206,11 +261,14 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
// to avoid preference height change.
|
||||
preference.setSummary(R.string.summary_placeholder);
|
||||
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SUMMARY_URI);
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SUMMARY_URI,
|
||||
METHOD_GET_DYNAMIC_SUMMARY);
|
||||
refreshSummary(uri, preference);
|
||||
return createDynamicDataObserver(METHOD_GET_DYNAMIC_SUMMARY, uri, preference);
|
||||
} else {
|
||||
preference.setSummary(R.string.summary_placeholder);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void refreshSummary(Uri uri, Preference preference) {
|
||||
@@ -222,6 +280,70 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private DynamicDataObserver bindSwitchAndGetObserver(Preference preference, Tile tile) {
|
||||
if (!tile.hasSwitch()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Uri onCheckedChangedUri = TileUtils.getCompleteUri(tile,
|
||||
META_DATA_PREFERENCE_SWITCH_URI, METHOD_ON_CHECKED_CHANGED);
|
||||
preference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
onCheckedChanged(onCheckedChangedUri, pref, (boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
|
||||
final Uri isCheckedUri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SWITCH_URI,
|
||||
METHOD_IS_CHECKED);
|
||||
setSwitchEnabled(preference, false);
|
||||
refreshSwitch(isCheckedUri, preference);
|
||||
return createDynamicDataObserver(METHOD_IS_CHECKED, isCheckedUri, preference);
|
||||
}
|
||||
|
||||
private void onCheckedChanged(Uri uri, Preference pref, boolean checked) {
|
||||
setSwitchEnabled(pref, false);
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final Map<String, IContentProvider> providerMap = new ArrayMap<>();
|
||||
final Bundle result = TileUtils.putBooleanToUri(mContext, uri, providerMap,
|
||||
EXTRA_SWITCH_CHECKED_STATE, checked);
|
||||
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
setSwitchEnabled(pref, true);
|
||||
final boolean error = result.getBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR);
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSwitchChecked(pref, !checked);
|
||||
final String errorMsg = result.getString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE);
|
||||
if (!TextUtils.isEmpty(errorMsg)) {
|
||||
Toast.makeText(mContext, errorMsg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshSwitch(Uri uri, Preference preference) {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final Map<String, IContentProvider> providerMap = new ArrayMap<>();
|
||||
final boolean checked = TileUtils.getBooleanFromUri(mContext, uri, providerMap,
|
||||
EXTRA_SWITCH_CHECKED_STATE);
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
setSwitchChecked(preference, checked);
|
||||
setSwitchEnabled(preference, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void setSwitchChecked(Preference pref, boolean checked) {
|
||||
if (pref instanceof SwitchPreference) {
|
||||
((SwitchPreference) pref).setChecked(checked);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSwitchEnabled(Preference pref, boolean enabled) {
|
||||
pref.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void bindIcon(Preference preference, Tile tile, boolean forceRoundedIcon) {
|
||||
// Use preference context instead here when get icon from Tile, as we are using the context
|
||||
@@ -246,7 +368,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
packageName = intent.getComponent().getPackageName();
|
||||
}
|
||||
final Map<String, IContentProvider> providerMap = new ArrayMap<>();
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_ICON_URI);
|
||||
final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_ICON_URI,
|
||||
METHOD_GET_PROVIDER_ICON);
|
||||
final Pair<String, Integer> iconInfo = TileUtils.getIconFromUri(
|
||||
mContext, packageName, uri, providerMap);
|
||||
if (iconInfo == null) {
|
||||
|
@@ -17,11 +17,11 @@ package com.android.settings.dashboard;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -30,6 +30,7 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
@@ -41,6 +42,7 @@ import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.drawer.DashboardCategory;
|
||||
import com.android.settingslib.drawer.ProviderTile;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
|
||||
@@ -49,7 +51,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Base fragment for dashboard style UI containing a list of static and dynamic setting items.
|
||||
@@ -60,9 +62,11 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
BasePreferenceController.UiBlockListener {
|
||||
private static final String TAG = "DashboardFragment";
|
||||
|
||||
@VisibleForTesting
|
||||
final ArrayMap<String, List<DynamicDataObserver>> mDashboardTilePrefKeys = new ArrayMap<>();
|
||||
private final Map<Class, List<AbstractPreferenceController>> mPreferenceControllers =
|
||||
new ArrayMap<>();
|
||||
private final Set<String> mDashboardTilePrefKeys = new ArraySet<>();
|
||||
private final List<DynamicDataObserver> mRegisteredObservers = new ArrayList<>();
|
||||
private final List<AbstractPreferenceController> mControllers = new ArrayList<>();
|
||||
|
||||
private DashboardFeatureProvider mDashboardFeatureProvider;
|
||||
@@ -171,6 +175,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
mListeningToCategoryChange = true;
|
||||
((SettingsBaseActivity) activity).addCategoryListener(this);
|
||||
}
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
mDashboardTilePrefKeys.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(List::stream)
|
||||
.forEach(observer -> {
|
||||
if (!mRegisteredObservers.contains(observer)) {
|
||||
registerDynamicDataObserver(resolver, observer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -200,6 +213,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
unregisterDynamicDataObservers(new ArrayList<>(mRegisteredObservers));
|
||||
if (mListeningToCategoryChange) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity instanceof SettingsBaseActivity) {
|
||||
@@ -325,7 +339,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
* Refresh all preference items, including both static prefs from xml, and dynamic items from
|
||||
* DashboardCategory.
|
||||
*/
|
||||
private void refreshAllPreferences(final String TAG) {
|
||||
private void refreshAllPreferences(final String tag) {
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
// First remove old preferences.
|
||||
if (screen != null) {
|
||||
@@ -336,11 +350,11 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
// Add resource based tiles.
|
||||
displayResourceTiles();
|
||||
|
||||
refreshDashboardTiles(TAG);
|
||||
refreshDashboardTiles(tag);
|
||||
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
Log.d(TAG, "All preferences added, reporting fully drawn");
|
||||
Log.d(tag, "All preferences added, reporting fully drawn");
|
||||
activity.reportFullyDrawn();
|
||||
}
|
||||
|
||||
@@ -371,59 +385,62 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
/**
|
||||
* Refresh preference items backed by DashboardCategory.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void refreshDashboardTiles(final String TAG) {
|
||||
private void refreshDashboardTiles(final String tag) {
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
|
||||
final DashboardCategory category =
|
||||
mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
|
||||
if (category == null) {
|
||||
Log.d(TAG, "NO dashboard tiles for " + TAG);
|
||||
Log.d(tag, "NO dashboard tiles for " + tag);
|
||||
return;
|
||||
}
|
||||
final List<Tile> tiles = category.getTiles();
|
||||
if (tiles == null) {
|
||||
Log.d(TAG, "tile list is empty, skipping category " + category.key);
|
||||
Log.d(tag, "tile list is empty, skipping category " + category.key);
|
||||
return;
|
||||
}
|
||||
// Create a list to track which tiles are to be removed.
|
||||
final List<String> remove = new ArrayList<>(mDashboardTilePrefKeys);
|
||||
final Map<String, List<DynamicDataObserver>> remove = new ArrayMap(mDashboardTilePrefKeys);
|
||||
|
||||
// Install dashboard tiles.
|
||||
final boolean forceRoundedIcons = shouldForceRoundedIcon();
|
||||
for (Tile tile : tiles) {
|
||||
final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
Log.d(TAG, "tile does not contain a key, skipping " + tile);
|
||||
Log.d(tag, "tile does not contain a key, skipping " + tile);
|
||||
continue;
|
||||
}
|
||||
if (!displayTile(tile)) {
|
||||
continue;
|
||||
}
|
||||
if (mDashboardTilePrefKeys.contains(key)) {
|
||||
if (mDashboardTilePrefKeys.containsKey(key)) {
|
||||
// Have the key already, will rebind.
|
||||
final Preference preference = screen.findPreference(key);
|
||||
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons,
|
||||
getMetricsCategory(), preference, tile, key,
|
||||
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
|
||||
forceRoundedIcons, getMetricsCategory(), preference, tile, key,
|
||||
mPlaceholderPreferenceController.getOrder());
|
||||
} else {
|
||||
// Don't have this key, add it.
|
||||
final Preference pref = new Preference(getPrefContext());
|
||||
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons,
|
||||
getMetricsCategory(), pref, tile, key,
|
||||
mPlaceholderPreferenceController.getOrder());
|
||||
final Preference pref = createPreference(tile);
|
||||
final List<DynamicDataObserver> observers =
|
||||
mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
|
||||
forceRoundedIcons, getMetricsCategory(), pref, tile, key,
|
||||
mPlaceholderPreferenceController.getOrder());
|
||||
screen.addPreference(pref);
|
||||
mDashboardTilePrefKeys.add(key);
|
||||
registerDynamicDataObservers(observers);
|
||||
mDashboardTilePrefKeys.put(key, observers);
|
||||
}
|
||||
remove.remove(key);
|
||||
}
|
||||
// Finally remove tiles that are gone.
|
||||
for (String key : remove) {
|
||||
for (Map.Entry<String, List<DynamicDataObserver>> entry : remove.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
mDashboardTilePrefKeys.remove(key);
|
||||
final Preference preference = screen.findPreference(key);
|
||||
if (preference != null) {
|
||||
screen.removePreference(preference);
|
||||
}
|
||||
unregisterDynamicDataObservers(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,4 +448,41 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
public void onBlockerWorkFinished(BasePreferenceController controller) {
|
||||
mBlockerController.countDown(controller.getPreferenceKey());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Preference createPreference(Tile tile) {
|
||||
return tile instanceof ProviderTile
|
||||
? new SwitchPreference(getPrefContext())
|
||||
: new Preference(getPrefContext());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void registerDynamicDataObservers(List<DynamicDataObserver> observers) {
|
||||
if (observers == null || observers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
observers.forEach(observer -> registerDynamicDataObserver(resolver, observer));
|
||||
}
|
||||
|
||||
private void registerDynamicDataObserver(ContentResolver resolver,
|
||||
DynamicDataObserver observer) {
|
||||
Log.d(TAG, "register observer: @" + Integer.toHexString(observer.hashCode())
|
||||
+ ", uri: " + observer.getUri());
|
||||
resolver.registerContentObserver(observer.getUri(), false, observer);
|
||||
mRegisteredObservers.add(observer);
|
||||
}
|
||||
|
||||
private void unregisterDynamicDataObservers(List<DynamicDataObserver> observers) {
|
||||
if (observers == null || observers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
observers.forEach(observer -> {
|
||||
Log.d(TAG, "unregister observer: @" + Integer.toHexString(observer.hashCode())
|
||||
+ ", uri: " + observer.getUri());
|
||||
mRegisteredObservers.remove(observer);
|
||||
resolver.unregisterContentObserver(observer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
42
src/com/android/settings/dashboard/DynamicDataObserver.java
Normal file
42
src/com/android/settings/dashboard/DynamicDataObserver.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.dashboard;
|
||||
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* Observer for updating injected dynamic data.
|
||||
*/
|
||||
public abstract class DynamicDataObserver extends ContentObserver {
|
||||
|
||||
protected DynamicDataObserver() {
|
||||
super(new Handler(Looper.getMainLooper()));
|
||||
}
|
||||
|
||||
/** Returns the uri of the callback. */
|
||||
public abstract Uri getUri();
|
||||
|
||||
/** Called when data changes. */
|
||||
public abstract void onDataChanged();
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
onDataChanged();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user