Group injected tiles together based on package name.

During grouping, tiles are sorted based on package name, and their own
priority value. However if the package is Settings itself, the ordering
is not changed.

Before sort: [pkg1, 100], [pgk2, 120], [pkg1, 130]
After sort: [pkg1, 1], [pkg1, 2], [pkg2,3]

This is necessary to make sure settings app have the overall control of
ordering of all dynamic tiles. When each app define their priority, they
don't have access to the global vision of what other settings are on
screen so it's possible different app define conflicting orderings.
Settings app is the only reasonable place to rank them properly.

Bug: 32827787
Test: RunSettingsLibRoboTests
Change-Id: I38de55530e61da9de7532ef6a7ee97ef89aca9d9
This commit is contained in:
Fan Zhang
2016-11-14 09:48:06 -08:00
parent 04c0d2b568
commit fc76ab3cbf
2 changed files with 170 additions and 0 deletions

View File

@@ -18,6 +18,7 @@ package com.android.settingslib.drawer;
import android.content.ComponentName;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -25,12 +26,15 @@ import android.util.Pair;
import com.android.settingslib.applications.InterestingConfigChanges;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
public class CategoryManager {
private static final String TAG = "CategoryManager";
@@ -111,6 +115,7 @@ public class CategoryManager {
mCategoryByKeyMap.put(category.key, category);
}
backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
normalizePriority(context, mCategoryByKeyMap);
}
}
@@ -163,4 +168,57 @@ public class CategoryManager {
}
}
}
/**
* Normalize priority values on tiles across injected from all apps to make sure they don't set
* the same priority value. However internal tiles' priority remains unchanged.
* <p/>
* A list of tiles are considered normalized when their priority value increases in a linear
* scan.
*/
@VisibleForTesting
synchronized void normalizePriority(Context context,
Map<String, DashboardCategory> categoryByKeyMap) {
for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
normalizePriorityForExternalTiles(context, categoryEntry.getValue());
}
}
/**
* Normalize priority value for tiles within a single {@code DashboardCategory}.
*
* @see #normalizePriority(Context, Map)
*/
private synchronized void normalizePriorityForExternalTiles(Context context,
DashboardCategory dashboardCategory) {
final String skipPackageName = context.getPackageName();
// Sort tiles based on [package, priority within package]
Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> {
final String package1 = tile1.intent.getComponent().getPackageName();
final String package2 = tile2.intent.getComponent().getPackageName();
final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2);
// First sort by package name
if (packageCompare != 0) {
return packageCompare;
} else if (TextUtils.equals(package1, skipPackageName)) {
return 0;
}
// Then sort by priority
return tile1.priority - tile2.priority;
});
// Update priority for all items so no package define the same priority value.
final int count = dashboardCategory.tiles.size();
for (int i = 0; i < count; i++) {
final String packageName =
dashboardCategory.tiles.get(i).intent.getComponent().getPackageName();
if (TextUtils.equals(packageName, skipPackageName)) {
// We skip this tile because it's a intent pointing to our own app. We trust the
// priority is set correctly, so don't normalize.
continue;
}
dashboardCategory.tiles.get(i).priority = i;
}
}
}

View File

@@ -16,7 +16,9 @@
package com.android.settingslib.drawer;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Pair;
import com.android.settingslib.TestConfig;
@@ -116,4 +118,114 @@ public class CategoryManagerTest {
// Old category still exists.
assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1);
}
@Test
public void normalizePriority_singlePackage_shouldReorderBasedOnPriority() {
// Create some fake tiles that are not sorted.
final String testPackage = "com.android.test";
final DashboardCategory category = new DashboardCategory();
final Tile tile1 = new Tile();
tile1.intent =
new Intent().setComponent(new ComponentName(testPackage, "class1"));
tile1.priority = 100;
final Tile tile2 = new Tile();
tile2.intent =
new Intent().setComponent(new ComponentName(testPackage, "class2"));
tile2.priority = 50;
final Tile tile3 = new Tile();
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile3.priority = 200;
category.tiles.add(tile1);
category.tiles.add(tile2);
category.tiles.add(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Normalize their priorities
mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
mCategoryByKeyMap);
// Verify they are now sorted.
assertThat(category.tiles.get(0)).isSameAs(tile2);
assertThat(category.tiles.get(1)).isSameAs(tile1);
assertThat(category.tiles.get(2)).isSameAs(tile3);
// Verify their priority is normalized
assertThat(category.tiles.get(0).priority).isEqualTo(0);
assertThat(category.tiles.get(1).priority).isEqualTo(1);
assertThat(category.tiles.get(2).priority).isEqualTo(2);
}
@Test
public void normalizePriority_multiPackage_shouldReorderBasedOnPackageAndPriority() {
// Create some fake tiles that are not sorted.
final String testPackage1 = "com.android.test1";
final String testPackage2 = "com.android.test2";
final DashboardCategory category = new DashboardCategory();
final Tile tile1 = new Tile();
tile1.intent =
new Intent().setComponent(new ComponentName(testPackage2, "class1"));
tile1.priority = 100;
final Tile tile2 = new Tile();
tile2.intent =
new Intent().setComponent(new ComponentName(testPackage1, "class2"));
tile2.priority = 100;
final Tile tile3 = new Tile();
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage1, "class3"));
tile3.priority = 50;
category.tiles.add(tile1);
category.tiles.add(tile2);
category.tiles.add(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Normalize their priorities
mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
mCategoryByKeyMap);
// Verify they are now sorted.
assertThat(category.tiles.get(0)).isSameAs(tile3);
assertThat(category.tiles.get(1)).isSameAs(tile2);
assertThat(category.tiles.get(2)).isSameAs(tile1);
// Verify their priority is normalized
assertThat(category.tiles.get(0).priority).isEqualTo(0);
assertThat(category.tiles.get(1).priority).isEqualTo(1);
assertThat(category.tiles.get(2).priority).isEqualTo(2);
}
@Test
public void normalizePriority_internalPackageTiles_shouldSkipTileForInternalPackage() {
// Create some fake tiles that are not sorted.
final String testPackage =
ShadowApplication.getInstance().getApplicationContext().getPackageName();
final DashboardCategory category = new DashboardCategory();
final Tile tile1 = new Tile();
tile1.intent =
new Intent().setComponent(new ComponentName(testPackage, "class1"));
tile1.priority = 100;
final Tile tile2 = new Tile();
tile2.intent =
new Intent().setComponent(new ComponentName(testPackage, "class2"));
tile2.priority = 100;
final Tile tile3 = new Tile();
tile3.intent =
new Intent().setComponent(new ComponentName(testPackage, "class3"));
tile3.priority = 50;
category.tiles.add(tile1);
category.tiles.add(tile2);
category.tiles.add(tile3);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
// Normalize their priorities
mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
mCategoryByKeyMap);
// Verify the sorting order is not changed
assertThat(category.tiles.get(0)).isSameAs(tile1);
assertThat(category.tiles.get(1)).isSameAs(tile2);
assertThat(category.tiles.get(2)).isSameAs(tile3);
// Verify their priorities are not changed.
assertThat(category.tiles.get(0).priority).isEqualTo(100);
assertThat(category.tiles.get(1).priority).isEqualTo(100);
assertThat(category.tiles.get(2).priority).isEqualTo(50);
}
}