Add activityInfo and getIcon() method in Tile class.
Moved loading icon logic from TileUtils into Tile#getIcon(). TileUtils only load things once and cache forever but getIcon() loads a fresh icon every time to avoid any caching issue. Bug: 77600770 Test: robotests Change-Id: I706225e382ebd5b72e91edef43bfc7427fa64590
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -17,17 +17,19 @@
|
||||
package com.android.settingslib.drawer;
|
||||
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
|
||||
import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -36,24 +38,23 @@ import java.util.ArrayList;
|
||||
*/
|
||||
public class Tile implements Parcelable {
|
||||
|
||||
private static final String TAG = "Tile";
|
||||
private ActivityInfo mActivityInfo;
|
||||
|
||||
/**
|
||||
* Title of the tile that is shown to the user.
|
||||
*
|
||||
* @attr ref android.R.styleable#PreferenceHeader_title
|
||||
*/
|
||||
public CharSequence title;
|
||||
|
||||
/**
|
||||
* Optional summary describing what this tile controls.
|
||||
*
|
||||
* @attr ref android.R.styleable#PreferenceHeader_summary
|
||||
*/
|
||||
public CharSequence summary;
|
||||
|
||||
/**
|
||||
* Optional icon to show for this tile.
|
||||
* @attr ref android.R.styleable#PreferenceHeader_icon
|
||||
*/
|
||||
public Icon icon;
|
||||
|
||||
/**
|
||||
* Whether the icon can be tinted. This should be set to true for monochrome (single-color)
|
||||
* icons that can be tinted to match the design.
|
||||
@@ -95,8 +96,8 @@ public class Tile implements Parcelable {
|
||||
*/
|
||||
public String key;
|
||||
|
||||
public Tile() {
|
||||
// Empty
|
||||
public Tile(ActivityInfo activityInfo) {
|
||||
mActivityInfo = activityInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,14 +107,9 @@ public class Tile implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(mActivityInfo, flags);
|
||||
TextUtils.writeToParcel(title, dest, flags);
|
||||
TextUtils.writeToParcel(summary, dest, flags);
|
||||
if (icon != null) {
|
||||
dest.writeByte((byte) 1);
|
||||
icon.writeToParcel(dest, flags);
|
||||
} else {
|
||||
dest.writeByte((byte) 0);
|
||||
}
|
||||
if (intent != null) {
|
||||
dest.writeByte((byte) 1);
|
||||
intent.writeToParcel(dest, flags);
|
||||
@@ -133,12 +129,36 @@ public class Tile implements Parcelable {
|
||||
dest.writeBoolean(isIconTintable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional icon to show for this tile.
|
||||
*
|
||||
* @attr ref android.R.styleable#PreferenceHeader_icon
|
||||
*/
|
||||
public Icon getIcon() {
|
||||
if (mActivityInfo == null || metaData == null) {
|
||||
return null;
|
||||
}
|
||||
int iconResId = metaData.getInt(META_DATA_PREFERENCE_ICON);
|
||||
// Set the icon
|
||||
if (iconResId == 0) {
|
||||
// Only fallback to activityinfo.icon if metadata does not contain ICON_URI.
|
||||
// ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
|
||||
// level is too complex because we don't have a strong threading contract for this class
|
||||
if (!metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
|
||||
iconResId = mActivityInfo.icon;
|
||||
}
|
||||
}
|
||||
if (iconResId != 0) {
|
||||
return Icon.createWithResource(mActivityInfo.packageName, iconResId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFromParcel(Parcel in) {
|
||||
mActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
|
||||
title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
if (in.readByte() != 0) {
|
||||
icon = Icon.CREATOR.createFromParcel(in);
|
||||
}
|
||||
if (in.readByte() != 0) {
|
||||
intent = Intent.CREATOR.createFromParcel(in);
|
||||
}
|
||||
@@ -162,6 +182,7 @@ public class Tile implements Parcelable {
|
||||
public Tile createFromParcel(Parcel source) {
|
||||
return new Tile(source);
|
||||
}
|
||||
|
||||
public Tile[] newArray(int size) {
|
||||
return new Tile[size];
|
||||
}
|
||||
@@ -169,7 +190,7 @@ public class Tile implements Parcelable {
|
||||
|
||||
public boolean isPrimaryProfileOnly() {
|
||||
String profile = metaData != null ?
|
||||
metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL;
|
||||
metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL;
|
||||
profile = (profile != null ? profile : PROFILE_ALL);
|
||||
return TextUtils.equals(profile, PROFILE_PRIMARY);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
@@ -303,7 +302,7 @@ public class TileUtils {
|
||||
Pair<String, String> key = new Pair<>(activityInfo.packageName, activityInfo.name);
|
||||
Tile tile = addedCache.get(key);
|
||||
if (tile == null) {
|
||||
tile = new Tile();
|
||||
tile = new Tile(activityInfo);
|
||||
tile.intent = new Intent().setClassName(
|
||||
activityInfo.packageName, activityInfo.name);
|
||||
tile.category = categoryKey;
|
||||
@@ -329,7 +328,6 @@ public class TileUtils {
|
||||
boolean forceTintExternalIcon) {
|
||||
if (applicationInfo.isSystemApp()) {
|
||||
boolean forceTintIcon = false;
|
||||
int icon = 0;
|
||||
CharSequence title = null;
|
||||
String summary = null;
|
||||
String keyHint = null;
|
||||
@@ -347,9 +345,6 @@ public class TileUtils {
|
||||
}
|
||||
|
||||
if (res != null && metaData != null) {
|
||||
if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
|
||||
icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
|
||||
}
|
||||
if (metaData.containsKey(META_DATA_PREFERENCE_ICON_TINTABLE)) {
|
||||
if (forceTintIcon) {
|
||||
Log.w(LOG_TAG, "Ignoring icon tintable for " + activityInfo);
|
||||
@@ -390,18 +385,6 @@ public class TileUtils {
|
||||
title = activityInfo.loadLabel(pm).toString();
|
||||
}
|
||||
|
||||
// Set the icon
|
||||
if (icon == 0) {
|
||||
// Only fallback to activityinfo.icon if metadata does not contain ICON_URI.
|
||||
// ICON_URI should be loaded in app UI when need the icon object.
|
||||
if (!tile.metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
|
||||
icon = activityInfo.icon;
|
||||
}
|
||||
}
|
||||
if (icon != 0) {
|
||||
tile.icon = Icon.createWithResource(activityInfo.packageName, icon);
|
||||
}
|
||||
|
||||
// Set title and summary for the preference
|
||||
tile.title = title;
|
||||
tile.summary = summary;
|
||||
|
||||
@@ -16,8 +16,16 @@
|
||||
|
||||
package com.android.settingslib.drawer;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -30,12 +38,6 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ProfileSelectDialogTest {
|
||||
@@ -58,7 +60,7 @@ public class ProfileSelectDialogTest {
|
||||
|
||||
@Test
|
||||
public void testUpdateUserHandlesIfNeeded_Normal() {
|
||||
final Tile tile = new Tile();
|
||||
final Tile tile = new Tile(new ActivityInfo());
|
||||
tile.intent = new Intent();
|
||||
tile.userHandle.add(NORMAL_USER);
|
||||
|
||||
@@ -71,7 +73,7 @@ public class ProfileSelectDialogTest {
|
||||
|
||||
@Test
|
||||
public void testUpdateUserHandlesIfNeeded_Remove() {
|
||||
final Tile tile = new Tile();
|
||||
final Tile tile = new Tile(new ActivityInfo());
|
||||
tile.intent = new Intent();
|
||||
tile.userHandle.add(REMOVED_USER);
|
||||
tile.userHandle.add(NORMAL_USER);
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
package com.android.settingslib.drawer;
|
||||
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
|
||||
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
|
||||
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
|
||||
import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.R;
|
||||
import com.android.settingslib.SettingsLibRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
|
||||
@RunWith(SettingsLibRobolectricTestRunner.class)
|
||||
public class TileTest {
|
||||
|
||||
private ActivityInfo mActivityInfo;
|
||||
private Tile mTile;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mTile = new Tile();
|
||||
mActivityInfo = new ActivityInfo();
|
||||
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
|
||||
mActivityInfo.icon = R.drawable.ic_plus;
|
||||
mTile = new Tile(mActivityInfo);
|
||||
mTile.metaData = new Bundle();
|
||||
}
|
||||
|
||||
@@ -47,4 +57,34 @@ public class TileTest {
|
||||
mTile.metaData = null;
|
||||
assertThat(mTile.isPrimaryProfileOnly()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIcon_noActivityOrMetadata_returnNull() {
|
||||
final Tile tile1 = new Tile((ActivityInfo) null);
|
||||
assertThat(tile1.getIcon()).isNull();
|
||||
|
||||
final Tile tile2 = new Tile(new ActivityInfo());
|
||||
assertThat(tile2.getIcon()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIcon_providedByUri_returnNull() {
|
||||
mTile.metaData.putString(META_DATA_PREFERENCE_ICON_URI, "content://foobar/icon");
|
||||
|
||||
assertThat(mTile.getIcon()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIcon_hasIconMetadata_returnIcon() {
|
||||
mTile.metaData.putInt(META_DATA_PREFERENCE_ICON, R.drawable.ic_info);
|
||||
|
||||
assertThat(mTile.getIcon().getResId()).isEqualTo(R.drawable.ic_info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIcon_noIconMetadata_returnActivityIcon() {
|
||||
mTile.metaData.putInt(META_DATA_PREFERENCE_ICON, 0);
|
||||
|
||||
assertThat(mTile.getIcon().getResId()).isEqualTo(mActivityInfo.icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public class TileUtilsTest {
|
||||
false /* checkCategory */, true /* forceTintExternalIcon */);
|
||||
|
||||
assertThat(outTiles.size()).isEqualTo(1);
|
||||
assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
|
||||
assertThat(outTiles.get(0).getIcon().getResId()).isEqualTo(314159);
|
||||
assertThat(outTiles.get(0).summary).isEqualTo("static-summary");
|
||||
|
||||
// Case 2: Empty bundle.
|
||||
@@ -332,7 +332,7 @@ public class TileUtilsTest {
|
||||
false /* checkCategory */, true /* forceTintExternalIcon */);
|
||||
|
||||
assertThat(outTiles.size()).isEqualTo(1);
|
||||
assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
|
||||
assertThat(outTiles.get(0).getIcon().getResId()).isEqualTo(314159);
|
||||
assertThat(outTiles.get(0).summary).isEqualTo("static-summary");
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ public class InputMethodAndSubtypeUtilCompatTest {
|
||||
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
|
||||
createDummyIme(false, false, createDummySubtype("keyboard", false, true))))
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
private static InputMethodInfo createDummyIme(boolean isSystem, boolean isAuxIme,
|
||||
InputMethodSubtype... subtypes) {
|
||||
@@ -254,7 +254,7 @@ public class InputMethodAndSubtypeUtilCompatTest {
|
||||
si.exported = true;
|
||||
si.nonLocalizedLabel = "Dummy IME";
|
||||
ri.serviceInfo = si;
|
||||
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
|
||||
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
|
||||
}
|
||||
|
||||
private static InputMethodSubtype createDummySubtype(
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ThreadUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostOnMainThread_shouldRunOnMainTread() throws Exception {
|
||||
public void testPostOnMainThread_shouldRunOnMainTread() {
|
||||
TestRunnable cr = new TestRunnable();
|
||||
ShadowLooper.pauseMainLooper();
|
||||
ThreadUtils.postOnMainThread(cr);
|
||||
|
||||
Reference in New Issue
Block a user