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: Ia334ab14dd3aa48c0d48ad6adcfd50ecfcb3400a
This commit is contained in:
Jason Chiu
2020-10-12 04:32:12 +00:00
committed by Automerger Merge Worker
3 changed files with 126 additions and 20 deletions

View File

@@ -41,11 +41,14 @@ import androidx.fragment.app.FragmentActivity;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SubSettings; import com.android.settings.SubSettings;
import com.android.settings.dashboard.CategoryManager; import com.android.settings.dashboard.CategoryManager;
import com.android.settingslib.drawer.Tile;
import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupcompat.util.WizardManagerHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
public class SettingsBaseActivity extends FragmentActivity { public class SettingsBaseActivity extends FragmentActivity {
@@ -59,6 +62,7 @@ public class SettingsBaseActivity extends FragmentActivity {
private final PackageReceiver mPackageReceiver = new PackageReceiver(); private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>(); private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
private int mCategoriesUpdateTaskCount;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -147,10 +151,10 @@ public class SettingsBaseActivity extends FragmentActivity {
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params); ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
} }
private void onCategoriesChanged() { private void onCategoriesChanged(Set<String> categories) {
final int N = mCategoryListeners.size(); final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged(); mCategoryListeners.get(i).onCategoriesChanged(categories);
} }
} }
@@ -194,38 +198,100 @@ public class SettingsBaseActivity extends FragmentActivity {
* Updates dashboard categories. Only necessary to call this after setTileEnabled * Updates dashboard categories. Only necessary to call this after setTileEnabled
*/ */
public void updateCategories() { 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 { 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 final CategoryManager mCategoryManager;
private Map<ComponentName, Tile> mPreviousTileMap;
public CategoriesUpdateTask() { public CategoriesUpdateTask() {
mCategoryManager = CategoryManager.get(SettingsBaseActivity.this); mCategoriesUpdateTaskCount++;
mContext = SettingsBaseActivity.this;
mCategoryManager = CategoryManager.get(mContext);
} }
@Override @Override
protected Void doInBackground(Void... params) { protected Set<String> doInBackground(Boolean... params) {
mCategoryManager.reloadAllCategories(SettingsBaseActivity.this); mPreviousTileMap = mCategoryManager.getTileByComponentMap();
mCategoryManager.reloadAllCategories(mContext);
mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
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; return null;
} }
@Override final Set<String> changedCategories = new ArraySet<>();
protected void onPostExecute(Void result) { final Map<ComponentName, Tile> currentTileMap =
mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist); mCategoryManager.getTileByComponentMap();
onCategoriesChanged(); 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 { private class PackageReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
updateCategories(); updateCategories(true /* fromBroadcast */);
} }
} }
} }

View File

@@ -41,6 +41,7 @@ import java.util.Set;
public class CategoryManager { public class CategoryManager {
private static final String TAG = "CategoryManager"; private static final String TAG = "CategoryManager";
private static final boolean DEBUG = false;
private static CategoryManager sInstance; private static CategoryManager sInstance;
private final InterestingConfigChanges mInterestingConfigChanges; private final InterestingConfigChanges mInterestingConfigChanges;
@@ -88,6 +89,7 @@ public class CategoryManager {
public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) { public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
if (mCategories == null) { if (mCategories == null) {
Log.w(TAG, "Category is null, skipping blacklist update"); Log.w(TAG, "Category is null, skipping blacklist update");
return;
} }
for (int i = 0; i < mCategories.size(); i++) { for (int i = 0; i < mCategories.size(); i++) {
DashboardCategory category = mCategories.get(i); DashboardCategory category = mCategories.get(i);
@@ -100,6 +102,31 @@ public class CategoryManager {
} }
} }
/** 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) { private synchronized void tryInitCategories(Context context) {
// Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
// happens. // happens.
@@ -108,6 +135,7 @@ public class CategoryManager {
private synchronized void tryInitCategories(Context context, boolean forceClearCache) { private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
if (mCategories == null) { if (mCategories == null) {
final boolean firstLoading = mCategoryByKeyMap.isEmpty();
if (forceClearCache) { if (forceClearCache) {
mTileByComponentCache.clear(); mTileByComponentCache.clear();
} }
@@ -119,6 +147,9 @@ public class CategoryManager {
backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
sortCategories(context, mCategoryByKeyMap); sortCategories(context, mCategoryByKeyMap);
filterDuplicateTiles(mCategoryByKeyMap); filterDuplicateTiles(mCategoryByKeyMap);
if (firstLoading) {
logTiles(context);
}
} }
} }

View File

@@ -56,6 +56,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
/** /**
@@ -160,13 +161,21 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
} }
@Override @Override
public void onCategoriesChanged() { public void onCategoriesChanged(Set<String> categories) {
final DashboardCategory category = final String categoryKey = getCategoryKey();
mDashboardFeatureProvider.getTilesForCategory(getCategoryKey()); final DashboardCategory dashboardCategory =
if (category == null) { mDashboardFeatureProvider.getTilesForCategory(categoryKey);
if (dashboardCategory == null) {
return; return;
} }
if (categories == null) {
// force refreshing
refreshDashboardTiles(getLogTag()); refreshDashboardTiles(getLogTag());
} else if (categories.contains(categoryKey)) {
Log.i(TAG, "refresh tiles for " + categoryKey);
refreshDashboardTiles(getLogTag());
}
} }
@Override @Override