Reduce the flickering of injected items when package is changed am: e4b2b77452
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/12771880
Change-Id: Ib2ff68b59e8aa9567d1f6f7c7281832dd323c2dc
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index 57697a6..199034c 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -41,11 +41,14 @@
import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.dashboard.CategoryManager;
+import com.android.settingslib.drawer.Tile;
import com.google.android.setupcompat.util.WizardManagerHelper;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class SettingsBaseActivity extends FragmentActivity {
@@ -59,6 +62,7 @@
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
+ private int mCategoriesUpdateTaskCount;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -147,10 +151,10 @@
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- private void onCategoriesChanged() {
+ private void onCategoriesChanged(Set<String> categories) {
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
- mCategoryListeners.get(i).onCategoriesChanged();
+ mCategoryListeners.get(i).onCategoriesChanged(categories);
}
}
@@ -194,38 +198,100 @@
* Updates dashboard categories. Only necessary to call this after setTileEnabled
*/
public void updateCategories() {
- new CategoriesUpdateTask().execute();
+ updateCategories(false /* fromBroadcast */);
+ }
+
+ private void updateCategories(boolean fromBroadcast) {
+ // Only allow at most 2 tasks existing at the same time since when the first one is
+ // executing, there may be new data from the second update request.
+ // Ignore the third update request because the second task is still waiting for the first
+ // task to complete in a serial thread, which will get the latest data.
+ if (mCategoriesUpdateTaskCount < 2) {
+ new CategoriesUpdateTask().execute(fromBroadcast);
+ }
}
public interface CategoryListener {
- void onCategoriesChanged();
+ /**
+ * @param categories the changed categories that have to be refreshed, or null to force
+ * refreshing all.
+ */
+ void onCategoriesChanged(@Nullable Set<String> categories);
}
- private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
+ private class CategoriesUpdateTask extends AsyncTask<Boolean, Void, Set<String>> {
+ private final Context mContext;
private final CategoryManager mCategoryManager;
+ private Map<ComponentName, Tile> mPreviousTileMap;
public CategoriesUpdateTask() {
- mCategoryManager = CategoryManager.get(SettingsBaseActivity.this);
+ mCategoriesUpdateTaskCount++;
+ mContext = SettingsBaseActivity.this;
+ mCategoryManager = CategoryManager.get(mContext);
}
@Override
- protected Void doInBackground(Void... params) {
- mCategoryManager.reloadAllCategories(SettingsBaseActivity.this);
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
+ protected Set<String> doInBackground(Boolean... params) {
+ mPreviousTileMap = mCategoryManager.getTileByComponentMap();
+ mCategoryManager.reloadAllCategories(mContext);
mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
- onCategoriesChanged();
+ return getChangedCategories(params[0]);
+ }
+
+ @Override
+ protected void onPostExecute(Set<String> categories) {
+ if (categories == null || !categories.isEmpty()) {
+ onCategoriesChanged(categories);
+ }
+ mCategoriesUpdateTaskCount--;
+ }
+
+ // Return the changed categories that have to be refreshed, or null to force refreshing all.
+ private Set<String> getChangedCategories(boolean fromBroadcast) {
+ if (!fromBroadcast) {
+ // Always refresh for non-broadcast case.
+ return null;
+ }
+
+ final Set<String> changedCategories = new ArraySet<>();
+ final Map<ComponentName, Tile> currentTileMap =
+ mCategoryManager.getTileByComponentMap();
+ currentTileMap.forEach((component, currentTile) -> {
+ final Tile previousTile = mPreviousTileMap.get(component);
+ // Check if the tile is newly added.
+ if (previousTile == null) {
+ Log.i(TAG, "Tile added: " + component.flattenToShortString());
+ changedCategories.add(currentTile.getCategory());
+ return;
+ }
+
+ // Check if the title or summary has changed.
+ if (!TextUtils.equals(currentTile.getTitle(mContext),
+ previousTile.getTitle(mContext))
+ || !TextUtils.equals(currentTile.getSummary(mContext),
+ previousTile.getSummary(mContext))) {
+ Log.i(TAG, "Tile changed: " + component.flattenToShortString());
+ changedCategories.add(currentTile.getCategory());
+ }
+ });
+
+ // Check if any previous tile is removed.
+ final Set<ComponentName> removal = new ArraySet(mPreviousTileMap.keySet());
+ removal.removeAll(currentTileMap.keySet());
+ removal.forEach(component -> {
+ Log.i(TAG, "Tile removed: " + component.flattenToShortString());
+ changedCategories.add(mPreviousTileMap.get(component).getCategory());
+ });
+
+ return changedCategories;
}
}
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- updateCategories();
+ updateCategories(true /* fromBroadcast */);
}
}
}
diff --git a/src/com/android/settings/dashboard/CategoryManager.java b/src/com/android/settings/dashboard/CategoryManager.java
index 525b6f8..b66de9d 100644
--- a/src/com/android/settings/dashboard/CategoryManager.java
+++ b/src/com/android/settings/dashboard/CategoryManager.java
@@ -41,6 +41,7 @@
public class CategoryManager {
private static final String TAG = "CategoryManager";
+ private static final boolean DEBUG = false;
private static CategoryManager sInstance;
private final InterestingConfigChanges mInterestingConfigChanges;
@@ -88,6 +89,7 @@
public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
if (mCategories == null) {
Log.w(TAG, "Category is null, skipping blacklist update");
+ return;
}
for (int i = 0; i < mCategories.size(); i++) {
DashboardCategory category = mCategories.get(i);
@@ -100,6 +102,31 @@
}
}
+ /** Return the current tile map */
+ public synchronized Map<ComponentName, Tile> getTileByComponentMap() {
+ final Map<ComponentName, Tile> result = new ArrayMap<>();
+ if (mCategories == null) {
+ Log.w(TAG, "Category is null, no tiles");
+ return result;
+ }
+ mCategories.forEach(category -> {
+ for (int i = 0; i < category.getTilesCount(); i++) {
+ final Tile tile = category.getTile(i);
+ result.put(tile.getIntent().getComponent(), tile);
+ }
+ });
+ return result;
+ }
+
+ private void logTiles(Context context) {
+ if (DEBUG) {
+ getTileByComponentMap().forEach((component, tile) -> {
+ Log.d(TAG, "Tile: " + tile.getCategory().replace("com.android.settings.", "")
+ + ": " + tile.getTitle(context) + ", " + component.flattenToShortString());
+ });
+ }
+ }
+
private synchronized void tryInitCategories(Context context) {
// Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
// happens.
@@ -108,6 +135,7 @@
private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
if (mCategories == null) {
+ final boolean firstLoading = mCategoryByKeyMap.isEmpty();
if (forceClearCache) {
mTileByComponentCache.clear();
}
@@ -119,6 +147,9 @@
backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
sortCategories(context, mCategoryByKeyMap);
filterDuplicateTiles(mCategoryByKeyMap);
+ if (firstLoading) {
+ logTiles(context);
+ }
}
}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 8084038..69f1f1b 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -56,6 +56,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
/**
@@ -160,13 +161,21 @@
}
@Override
- public void onCategoriesChanged() {
- final DashboardCategory category =
- mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
- if (category == null) {
+ public void onCategoriesChanged(Set<String> categories) {
+ final String categoryKey = getCategoryKey();
+ final DashboardCategory dashboardCategory =
+ mDashboardFeatureProvider.getTilesForCategory(categoryKey);
+ if (dashboardCategory == null) {
return;
}
- refreshDashboardTiles(getLogTag());
+
+ if (categories == null) {
+ // force refreshing
+ refreshDashboardTiles(getLogTag());
+ } else if (categories.contains(categoryKey)) {
+ Log.i(TAG, "refresh tiles for " + categoryKey);
+ refreshDashboardTiles(getLogTag());
+ }
}
@Override