package com.android.settings.dashboard;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager.OnActivityResultListener;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreferenceCompat;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.CategoryMixin.CategoryHandler;
import com.android.settings.core.CategoryMixin.CategoryListener;
import com.android.settings.core.PreferenceControllerListHelper;
import com.android.settings.flags.Flags;
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.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.search.Indexable;
import com.android.settings.Utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import com.android.settingslib.drawer.CategoryKey;
import com.freeme.settings.preference.FreemePreference;
import com.freeme.settings.preference.FreemePreferenceCategory;
import com.freeme.settings.FreemeUtils;
import androidx.recyclerview.widget.RecyclerView;
import com.freeme.settings.LogUtils;
import com.freeme.settings.preference.FreemeSwitchPreference;
import com.freeme.settings.widget.FreemePrimarySwitchPreference;
/**
-
Base fragment for dashboard style UI containing a list of static and dynamic setting items.
*/
public abstract class DashboardFragment extends SettingsPreferenceFragment
implements CategoryListener, Indexable, PreferenceGroup.OnExpandButtonClickListener,
BasePreferenceController.UiBlockListener {
public static final String CATEGORY = “category”;
private static final String TAG = “DashboardFragment”;
private static final long TIMEOUT_MILLIS = 50L;@VisibleForTesting
final ArrayMap<String, List> mDashboardTilePrefKeys = new ArrayMap<>();
private final Map<Class, List> mPreferenceControllers =
new ArrayMap<>();
private final List mRegisteredObservers = new ArrayList<>();
private final List mControllers = new ArrayList<>();
@VisibleForTesting
UiBlockerController mBlockerController;
private DashboardFeatureProvider mDashboardFeatureProvider;
private DashboardTilePlaceholderPreferenceController mPlaceholderPreferenceController;
private boolean mListeningToCategoryChange;
private List mSuppressInjectedTileKeys;@Override
public void onAttach(Context context) {
super.onAttach(context);
mSuppressInjectedTileKeys = Arrays.asList(context.getResources().getStringArray(
R.array.config_suppress_injected_tile_keys));
mDashboardFeatureProvider =
FeatureFactory.getFeatureFactory().getDashboardFeatureProvider();
// Load preference controllers from code
final List controllersFromCode =
createPreferenceControllers(context);
// Load preference controllers from xml definition
final List controllersFromXml = PreferenceControllerListHelper
.getPreferenceControllersFromXml(context, getPreferenceScreenResId());
// Filter xml-based controllers in case a similar controller is created from code already.
final List uniqueControllerFromXml =
PreferenceControllerListHelper.filterControllers(
controllersFromXml, controllersFromCode);// Add unique controllers to list. if (controllersFromCode != null) { mControllers.addAll(controllersFromCode); } mControllers.addAll(uniqueControllerFromXml); // And wire up with lifecycle. final Lifecycle lifecycle = getSettingsLifecycle(); uniqueControllerFromXml.forEach(controller -> { if (controller instanceof LifecycleObserver) { lifecycle.addObserver((LifecycleObserver) controller); } }); // Set metrics category for BasePreferenceController. final int metricCategory = getMetricsCategory(); mControllers.forEach(controller -> { if (controller instanceof BasePreferenceController) { ((BasePreferenceController) controller).setMetricsCategory(metricCategory); } }); mPlaceholderPreferenceController = new DashboardTilePlaceholderPreferenceController(context); mControllers.add(mPlaceholderPreferenceController); for (AbstractPreferenceController controller : mControllers) { addPreferenceController(controller); }
}
@VisibleForTesting
void checkUiBlocker(List controllers) {
final List keys = new ArrayList<>();
final List baseControllers = new ArrayList<>();
controllers.forEach(controller -> {
if (controller instanceof BasePreferenceController.UiBlocker
&& controller.isAvailable()) {
((BasePreferenceController) controller).setUiBlockListener(this);
keys.add(controller.getPreferenceKey());
baseControllers.add((BasePreferenceController) controller);
}
});if (!keys.isEmpty()) { mBlockerController = new UiBlockerController(keys); mBlockerController.start(() -> { updatePreferenceVisibility(mPreferenceControllers); baseControllers.forEach(controller -> controller.setUiBlockerFinished(true)); }); }
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Set ComparisonCallback so we get better animation when list changes.
getPreferenceManager().setPreferenceComparisonCallback(
new PreferenceManager.SimplePreferenceComparisonCallback());
if (icicle != null) {
// Upon rotation configuration change we need to update preference states before any
// editing dialog is recreated (that would happen before onResume is called).
updatePreferenceStates();
}
}@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LifecycleOwner viewLifecycleOwner = getViewLifecycleOwner();
for (AbstractPreferenceController controller : mControllers) {
controller.onViewCreated(viewLifecycleOwner);
}
}@Override
public void onCategoriesChanged(Set categories) {
final String categoryKey = getCategoryKey();
final DashboardCategory dashboardCategory =
mDashboardFeatureProvider.getTilesForCategory(categoryKey);
if (dashboardCategory == null) {
return;
}if (categories == null) { // force refreshing refreshDashboardTiles(getLogTag()); } else if (categories.contains(categoryKey)) { Log.i(TAG, "refresh tiles for " + categoryKey); refreshDashboardTiles(getLogTag()); }
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
checkUiBlocker(mControllers);
refreshAllPreferences(getLogTag());
mControllers.stream()
.map(controller -> (Preference) findPreference(controller.getPreferenceKey()))
.filter(Objects::nonNull)
.forEach(preference -> {
// Give all controllers a chance to handle click.
preference.getExtras().putInt(CATEGORY, getMetricsCategory());
});
}@Override
public void onStart() {
super.onStart();
final DashboardCategory category =
mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
if (category == null) {
return;
}
final Activity activity = getActivity();
if (activity instanceof CategoryHandler) {
mListeningToCategoryChange = true;
((CategoryHandler) activity).getCategoryMixin().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
public void onResume() {
super.onResume();
updatePreferenceStates();
}@Override
public boolean onPreferenceTreeClick(Preference preference) {
final Collection<List> controllers =
mPreferenceControllers.values();
for (List controllerList : controllers) {
for (AbstractPreferenceController controller : controllerList) {
if (controller.handlePreferenceTreeClick(preference)) {
// log here since calling super.onPreferenceTreeClick will be skipped
writePreferenceClickMetric(preference);
return true;
}
}
}
return super.onPreferenceTreeClick(preference);
}@Override
public void onStop() {
super.onStop();
unregisterDynamicDataObservers(new ArrayList<>(mRegisteredObservers));
if (mListeningToCategoryChange) {
final Activity activity = getActivity();
if (activity instanceof CategoryHandler) {
((CategoryHandler) activity).getCategoryMixin().removeCategoryListener(this);
}
mListeningToCategoryChange = false;
}
}@Override
protected abstract int getPreferenceScreenResId();@Override
public void onExpandButtonClick() {
mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND,
getMetricsCategory(), null, 0);
}@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
for (List controllerList : mPreferenceControllers.values()) {
for (AbstractPreferenceController controller : controllerList) {
if (controller instanceof OnActivityResultListener) {
((OnActivityResultListener) controller).onActivityResult(
requestCode, resultCode, data);
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}protected boolean shouldForceRoundedIcon() {
return false;
}protected T use(Class clazz) {
List controllerList = mPreferenceControllers.get(clazz);
if (controllerList != null) {
if (controllerList.size() > 1) {
Log.w(TAG, “Multiple controllers of Class " + clazz.getSimpleName()
+ " found, returning first one.”);
}
return (T) controllerList.get(0);
}return null;
}
/** Returns all controllers of type T. */
protected List useAll(Class clazz) {
return (List) mPreferenceControllers.getOrDefault(clazz, Collections.emptyList());
}protected void addPreferenceController(AbstractPreferenceController controller) {
if (mPreferenceControllers.get(controller.getClass()) == null) {
mPreferenceControllers.put(controller.getClass(), new ArrayList<>());
}
mPreferenceControllers.get(controller.getClass()).add(controller);
}/**
- Returns the CategoryKey for loading {@link DashboardCategory} for this fragment.
*/
@VisibleForTesting
public String getCategoryKey() {
return DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP.get(getClass().getName());
}
/**
- Get the tag string for logging.
*/
protected abstract String getLogTag();
/**
- Get a list of {@link AbstractPreferenceController} for this fragment.
*/
protected List createPreferenceControllers(Context context) {
return null;
}
/**
- Returns true if this tile should be displayed
*/
@CallSuper
protected boolean displayTile(Tile tile) {
if (mSuppressInjectedTileKeys != null && tile.hasKey()) {
// For suppressing injected tiles for OEMs.
return !mSuppressInjectedTileKeys.contains(tile.getKey(getContext()));
}
return true;
}
/**
- Displays resource based tiles.
*/
private void displayResourceTiles() {
final int resId = getPreferenceScreenResId();
if (resId <= 0) {
return;
}
addPreferencesFromResource(resId);
final PreferenceScreen screen = getPreferenceScreen();
screen.setOnExpandButtonClickListener(this);
displayResourceTilesToScreen(screen);
}
/**
- Perform {@link AbstractPreferenceController#displayPreference(PreferenceScreen)}
- on all {@link AbstractPreferenceController}s.
*/
protected void displayResourceTilesToScreen(PreferenceScreen screen) {
mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach(
controller -> controller.displayPreference(screen));
}
/**
- Get current PreferenceController(s)
*/
protected Collection<List> getPreferenceControllers() {
return mPreferenceControllers.values();
}
/**
-
Update state of each preference managed by PreferenceController.
/
protected void updatePreferenceStates() {
final PreferenceScreen screen = getPreferenceScreen();
Collection<List> controllerLists =
mPreferenceControllers.values();
for (List controllerList : controllerLists) {
for (AbstractPreferenceController controller : controllerList) {
if (!controller.isAvailable()) {
/// freeme.yangtengfei, 20241114. Settings-dashboard: update if need
if (screen != null) controller.displayPreference(screen);
//*/
continue;
}final String key = controller.getPreferenceKey(); if (TextUtils.isEmpty(key)) { Log.d(TAG, String.format("Preference key is %s in Controller %s", key, controller.getClass().getSimpleName())); continue; } final Preference preference = screen.findPreference(key); if (preference == null) { Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s", key, controller.getClass().getSimpleName())); continue; } /* Bug 2702447, com.android.settings occur crash (MissingResourceException) @{ */ try { controller.updateState(preference); } catch (MissingResourceException | IllegalStateException e) { e.printStackTrace(); } /* @} */ }
}
}
/**
-
Refresh all preference items, including both static prefs from xml, and dynamic items from
-
DashboardCategory.
*/
private void refreshAllPreferences(final String tag) {
final PreferenceScreen screen = getPreferenceScreen();
// First remove old preferences.
if (screen != null) {
// Intentionally do not cache PreferenceScreen because it will be recreated later.
screen.removeAll();
}// Add resource based tiles.
displayResourceTiles();refreshDashboardTiles(tag);
final Activity activity = getActivity();
if (activity != null) {
Log.d(tag, “All preferences added, reporting fully drawn”);
activity.reportFullyDrawn();
}updatePreferenceVisibility(mPreferenceControllers);
}
/**
- Force update all the preferences in this fragment.
*/
public void forceUpdatePreferences() {
final PreferenceScreen screen = getPreferenceScreen();
if (screen == null || mPreferenceControllers == null) {
return;
}
for (List controllerList : mPreferenceControllers.values()) {
for (AbstractPreferenceController controller : controllerList) {
final String key = controller.getPreferenceKey();
final Preference preference = findPreference(key);
if (preference == null) {
continue;
}
final boolean available = controller.isAvailable();
if (available) {
controller.updateState(preference);
}
preference.setVisible(available);
}
}
}
@VisibleForTesting
void updatePreferenceVisibility(
Map<Class, List> preferenceControllers) {
final PreferenceScreen screen = getPreferenceScreen();
if (screen == null || preferenceControllers == null || mBlockerController == null) {
return;
}final boolean visible = mBlockerController.isBlockerFinished(); for (List<AbstractPreferenceController> controllerList : preferenceControllers.values()) { for (AbstractPreferenceController controller : controllerList) { final String key = controller.getPreferenceKey(); final Preference preference = findPreference(key); if (preference == null) { continue; } if (controller instanceof BasePreferenceController.UiBlocker) { final boolean prefVisible = ((BasePreferenceController) controller).getSavedPrefVisibility(); preference.setVisible(visible && controller.isAvailable() && prefVisible); } else { preference.setVisible(visible && controller.isAvailable()); } } }
}
/**
-
Refresh preference items backed by DashboardCategory.
*/
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);
return;
}
final List tiles = category.getTiles();
if (tiles == null) {
Log.d(tag, "tile list is empty, skipping category " + category.key);
return;
}
// Create a list to track which tiles are to be removed.
final Map<String, List> remove = new ArrayMap(mDashboardTilePrefKeys);// Install dashboard tiles and collect pending observers.
final boolean forceRoundedIcons = shouldForceRoundedIcon();
final List pendingObservers = new ArrayList<>();// Move group tiles to the beginning of the list to ensure they are created before the
// other tiles.
tiles.sort(Comparator.comparingInt(tile -> tile.getType() == Tile.Type.GROUP ? 0 : 1));
for (Tile tile : tiles) {
/// freeme.yangtengfei, 20240830. Settings-dynamicInsert: add filter packages
if (FreemeUtils.isFilterPackage(getContext(),
tile.getPackageName(), R.array.dynamic_insert_filter_pkgs)) continue;
///
/// freeme.caoguofeng, 20230712. add for injected tiles feature.
if (!FreemeUtils.isFeatureOn(getContext(), tile)) continue;
///
final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
if (TextUtils.isEmpty(key)) {
Log.d(tag, "tile does not contain a key, skipping " + tile);
continue;
}
if (!displayTile(tile)) {
continue;
}
final List observers;
if (mDashboardTilePrefKeys.containsKey(key)) {
// Have the key already, will rebind.
final Preference preference = screen.findPreference(key);
observers = mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(
getActivity(), this, forceRoundedIcons, preference, tile, key,
mPlaceholderPreferenceController.getOrder());
} else {
// Don’t have this key, add it.
final Preference pref = createPreference(tile);
/// freeme.caoguofeng, 20210320, freeme style
if (!getCategoryKey().equals(CategoryKey.CATEGORY_HOMEPAGE)) {
pref.setIcon(null);
}
///
observers = mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(
getActivity(), this, forceRoundedIcons, pref, tile, key,
mPlaceholderPreferenceController.getOrder());
if (Flags.dynamicInjectionCategory()) {
if (tile.hasGroupKey()) {
Preference group = screen.findPreference(tile.getGroupKey());
if (group instanceof PreferenceCategory) {
((PreferenceCategory) group).addPreference(pref);
} else {
screen.addPreference(pref);
}
} else {
screen.addPreference(pref);
}
} else {
if (tile.hasGroupKey()
&& mDashboardTilePrefKeys.containsKey(tile.getGroupKey())) {
Preference group = screen.findPreference(tile.getGroupKey());
if (group instanceof PreferenceCategory) {
((PreferenceCategory) group).addPreference(pref);
}
} else {
// freeme.xinyuwo, 20230823. Settings-freemetheme: freeme redesign 15.0.
screen.addPreference(pref);
//
if (getCategoryKey().equals(CategoryKey.CATEGORY_HOMEPAGE)) {
if (key.equals(“dashboard_tile_pref_com.freeme.healthcontrol.ui.activity.GuideActivity”)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_top_level_use”);
mfreemePreferenceCategory.addPreference(pref);
} else if (key.equals(“dashboard_tile_pref_com.zhuoyi.security.lite.newstyle.SettingsVipEntranceActivity”)) {
FreemePreferenceCategory preferenceCategory = screen.findPreference(
“top_level_security_vip_event_category”);
preferenceCategory.addPreference(pref);
if (!preferenceCategory.isVisible()) {
boolean visible = !TextUtils.isEmpty(pref.getTitle());
preferenceCategory.setVisible(visible);
if (visible) {
updateFirstPreference();
} else {
LogUtils.i(TAG, “remove when no data”);
preferenceCategory.removePreference(pref);
}
}
} else if (tile.isAD()) {
FreemePreferenceCategory preferenceCategory = screen.findPreference(
“top_level_security_vip_title_category”);
preferenceCategory.addPreference(pref);
if (!preferenceCategory.isVisible()) {
preferenceCategory.setVisible(true);
updateFirstPreference();
}
/// freeme.ligen, 20250709. modify google preference position
} else if (“top_level_wellbeing”.equals(pref.getKey())) {
FreemePreferenceCategory mUsePreferenceCategory =
screen.findPreference(“freeme_top_level_use”);
pref.setOrder(-145);
mUsePreferenceCategory.addPreference(pref);
///
} else {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_top_level_system”);
mfreemePreferenceCategory.addPreference(pref);
}
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_ADVANCED_FEATURES_SETTINGS)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“advanced_features_mode”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_SYSTEM)) {
if (key.equals(“dashboard_tile_pref_com.freeme.sysfeaturesettings.navigation.FreemeNavigationSettingsActivity”)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“system_settings_category”);
mfreemePreferenceCategory.addPreference(pref);
} else {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“advanced_category”);
mfreemePreferenceCategory.addPreference(pref);
}
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_NOTIFICATIONS)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“configure_notifications_advanced”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_DISPLAY)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_display_compat_settings_category”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_SECURITY)) {
if (key.equals(“dashboard_tile_pref_com.freeme.lockscreen.picker.LockscreenActivity”)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_security_settings”);
mfreemePreferenceCategory.addPreference(pref);
} else {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_security”);
mfreemePreferenceCategory.addPreference(pref);
}
} else if (getCategoryKey().equals(DashboardFragmentRegistry.CATEGORY_DATAUSAGE_SUMMARY)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“usage_title”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_ABOUT_LEGAL)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“freeme_about_legal”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_SECURITY_LOCKSCREEN)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“lockscreen_settings”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT) && !Utils.isMonkeyRunning()) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“debug_input_category”);
mfreemePreferenceCategory.addPreference(pref);
} else if (getCategoryKey().equals(CategoryKey.CATEGORY_APPS)) {
FreemePreferenceCategory mfreemePreferenceCategory = screen.findPreference(“no_label_preference_category”);
mfreemePreferenceCategory.addPreference(pref);
}else {
screen.addPreference(pref);
}
//*/
}
}
registerDynamicDataObservers(observers);
mDashboardTilePrefKeys.put(key, observers);
}
if (observers != null) {
pendingObservers.addAll(observers);
}
remove.remove(key);
}// Remove tiles that are gone.
for (Map.Entry<String, List> entry : remove.entrySet()) {
final String key = entry.getKey();
mDashboardTilePrefKeys.remove(key);
if (Flags.dynamicInjectionCategory()) {
screen.removePreferenceRecursively(key);
} else {
Preference preference = screen.findPreference(key);
if (preference != null) {
// freeme.yangtengfei, 20241224. Settings-dynamicInsert: delete when no support
screen.removePreference(preference);
//
PreferenceGroup parent = preference.getParent();
if (parent != null) {
parent.getPreferenceManager().setPreferenceComparisonCallback(null);
parent.removePreference(preference);
}
//*/
}
}
unregisterDynamicDataObservers(entry.getValue());
}// Wait for pending observers to update UI.
if (!pendingObservers.isEmpty()) {
final CountDownLatch mainLatch = new CountDownLatch(1);
new Thread(() -> {
pendingObservers.forEach(observer ->
awaitObserverLatch(observer.getCountDownLatch()));
mainLatch.countDown();
}).start();
Log.d(tag, “Start waiting observers”);
awaitObserverLatch(mainLatch);
Log.d(tag, “Stop waiting observers”);
pendingObservers.forEach(DynamicDataObserver::updateUi);
}
}
@Override
public void onBlockerWorkFinished(BasePreferenceController controller) {
mBlockerController.countDown(controller.getPreferenceKey());
controller.setUiBlockerFinished(mBlockerController.isBlockerFinished());
}protected Preference createPreference(Tile tile) {
switch (tile.getType()) {
case EXTERNAL_ACTION:
// freeme.yangtengfei, 20250220. Settings-init: adapt for A15
Preference externalActionPreference = new Preference(getPrefContext());
//
Preference externalActionPreference = new FreemePreference(getPrefContext());
///
externalActionPreference
.setWidgetLayoutResource(R.layout.preference_external_action_icon);
return externalActionPreference;
case SWITCH:
// freeme.yangtengfei, 20250310. Settings-init: adapt switch for A15
return new SwitchPreferenceCompat(getPrefContext());
//
return new FreemeSwitchPreference(getPrefContext());
///
case SWITCH_WITH_ACTION:
// freeme.yangtengfei, 20250220. Settings-init: adapt for A15
return new PrimarySwitchPreference(getPrefContext());
//
return new FreemePrimarySwitchPreference(getPrefContext());
///
case GROUP:
mMetricsFeatureProvider.action(
mMetricsFeatureProvider.getAttribution(getActivity()),
SettingsEnums.ACTION_SETTINGS_GROUP_TILE_ADDED_TO_SCREEN,
getMetricsCategory(),
tile.getKey(getContext()),
/ value= / 0);
return new PreferenceCategory((getPrefContext()));
case ACTION:
default:
// freeme.yangtengfei, 20250220. Settings-init: adapt for A15
return new Preference(getPrefContext());
//
return new FreemePreference(getPrefContext());
///
}
}@VisibleForTesting
void registerDynamicDataObservers(List 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());
// freeme.xinyuwo, 20240102. not register crash.
resolver.registerContentObserver(observer.getUri(), false, observer);
//
try {
resolver.registerContentObserver(observer.getUri(), false, observer);
} catch (SecurityException e) {
Log.d(TAG,“this uri not register”);
}
//*/
mRegisteredObservers.add(observer);
}private void unregisterDynamicDataObservers(List 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);
});
}private void awaitObserverLatch(CountDownLatch latch) {
try {
latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// Do nothing
}
}/// freeme.yangtengfei, 20240930. Settings-homepage: refresh first preference
private void updateFirstPreference() {
RecyclerView recyclerView = getListView();
if (recyclerView != null) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
adapter.notifyItemChanged(0);
}
}
}
///
} - Returns the CategoryKey for loading {@link DashboardCategory} for this fragment.