Reduce the flickering of injected items when package is changed am: e4b2b77452
am: fe66e87832
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/12771880 Change-Id: I51833ab9e852bedd3c5bb28dc233f142e66a3238
This commit is contained in:
@@ -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();
|
||||||
return null;
|
mCategoryManager.reloadAllCategories(mContext);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void result) {
|
|
||||||
mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
|
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 {
|
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 */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
refreshDashboardTiles(getLogTag());
|
|
||||||
|
if (categories == null) {
|
||||||
|
// force refreshing
|
||||||
|
refreshDashboardTiles(getLogTag());
|
||||||
|
} else if (categories.contains(categoryKey)) {
|
||||||
|
Log.i(TAG, "refresh tiles for " + categoryKey);
|
||||||
|
refreshDashboardTiles(getLogTag());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user