DashboardFragment

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);
    }
    }
    }
    //
    /
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值