为适配的各种UI,客户经常会对要求应用的图标进行替换、定制或修改。修改的方式有很多,效果也不尽相同,本文章将会把所有的修改方式与君解析。
目录
替换应用图标
一、Launcher层面修改
缺点:仅在Launcher界面上面显示的icon被修改了,setting和系统安装应用界面等还是原来的图标。
通过BubbleTextView.java修改
BubbleTextView.java这个类在Launcher运行阶段属于比较晚的,所以如果说有大量第三方应用图标需要替换的话,在Launcher启动时可能会出现卡顿。
代码路径:Launcher3/src/com/android/launcher3/BubbleTextView.java
基于Android9:
private void applyIconAndLabel(ItemInfoWithIcon info) {
//FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);
String pkg = info.getIntent().getComponent().getPackageName();
if("com.android.vending".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.player);
BitmapDrawable clock_drawable = new BitmapDrawable(bitmap);
if(clock_drawable!=null)setIcon(clock_drawable);
}else if("com.android.chrome".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.chrome);
BitmapDrawable clock_drawable = new BitmapDrawable(bitmap);
if(clock_drawable!=null)setIcon(clock_drawable);
}else{
FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);
setIcon(iconDrawable);
}
mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f);
//setIcon(iconDrawable);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
: info.contentDescription);
}
}
基于Android13:
代码路径:packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
...
...
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
|| mDisplay == DISPLAY_TASKBAR;
int flags = useTheme ? FLAG_THEMED : 0;
if (mHideBadge) {
flags |= FLAG_NO_BADGE;
}
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
mDotParams.appColor = iconDrawable.getIconColor();
mDotParams.dotColor = getContext().getResources()
.getColor(android.R.color.system_accent3_200, getContext().getTheme());
//add
//setIcon(iconDrawable);
String pkg = info.getIntent().getComponent().getPackageName();
String cls = info.getIntent().getComponent().getClassName();
if("com.android.vending".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_player);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.chrome".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_chrome);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.google.android.apps.nbu.files".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_files);
setIcon(new FastBitmapDrawable(bitmap));
}/* else if("com.android.fmradio".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_fmradio);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.gallery3d.app.GalleryActivity".equals(cls)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_gallery);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.cooliris.media.Gallery".equals(cls)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_video);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.soundrecorder".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_soundrecorder);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.deskclock".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_deskclock);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.calendar".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_calendar);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.music".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_music);
setIcon(new FastBitmapDrawable(bitmap));
}else if("com.android.calculator2".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_calculator2);
setIcon(new FastBitmapDrawable(bitmap));
} */else{
setIcon(iconDrawable);
}
//add
applyLabel(info);
}
通过IconCache.java修改
通过IconCache.java修改第三方应用图标,相比于BubbleTextView运行的更早并且可以单独修改应用图标的大小。
代码路径:Launcher3/src/com/android/launcher3/IconCache.java
基于Android9:
import android.support.v4.content.ContextCompat;
protected CacheEntry cacheLocked(
@NonNull ComponentName componentName,
@NonNull Provider<LauncherActivityInfo> infoProvider,
UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
Preconditions.assertWorkerThread();
ComponentKey cacheKey = new ComponentKey(componentName, user);
CacheEntry entry = mCache.get(cacheKey);
if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
entry = new CacheEntry();
mCache.put(cacheKey, entry);
// Check the DB first.
LauncherActivityInfo info = null;
boolean providerFetchedOnce = false;
if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
info = infoProvider.get();
providerFetchedOnce = true;
if (info != null) {
LauncherIcons li = LauncherIcons.obtain(mContext);
li.createBadgedIconBitmap(getFullResIcon(info), info.getUser(),
info.getApplicationInfo().targetSdkVersion).applyTo(entry);
li.recycle();
} else {
if (usePackageIcon) {
CacheEntry packageEntry = getEntryForPackageLocked(
componentName.getPackageName(), user, false);
if (packageEntry != null) {
if (DEBUG) Log.d(TAG, "using package default icon for " +
componentName.toShortString());
packageEntry.applyTo(entry);
entry.title = packageEntry.title;
entry.contentDescription = packageEntry.contentDescription;
}
}
if (entry.icon == null) {
if (DEBUG) Log.d(TAG, "using default icon for " +
componentName.toShortString());
getDefaultIcon(user).applyTo(entry);
}
}
}
if (TextUtils.isEmpty(entry.title)) {
if (info == null && !providerFetchedOnce) {
info = infoProvider.get();
providerFetchedOnce = true;
}
if (info != null) {
entry.title = info.getLabel();
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
}
}
}
/* if("com.google.android.inputmethod.latin".equals(componentName.getPackageName().toString())) {
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.inputmethod);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.apple.android.music".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.apple);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.spotify.music".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.spotify);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.audible.application".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.audible);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.amazon.mp3".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.amazon);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("deezer.android.app".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.deezer);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.android.chrome".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.chrome);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.android.vending".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.vending);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.hiby.music".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.hiby);
entry.icon = li.createIconBitmap(drawable,0.82f);
}else if("com.mxtech.videoplayer.pro".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.mxtech);
entry.icon = li.createIconBitmap(drawable,0.82f);
} */
if("com.mxtech.videoplayer.pro".equals(componentName.getPackageName().toString())){
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable drawable = ContextCompat.getDrawable(mContext, R.mipmap.mxtech);
entry.icon = li.createIconBitmap(drawable,0.82f);
}
return entry;
}
Launcher3/src/com/android/launcher3/graphics/LauncherIcons.java
- private Bitmap createIconBitmap(Drawable icon, float scale) {
+ public Bitmap createIconBitmap(Drawable icon, float scale) {
int width = mIconBitmapSize;
int height = mIconBitmapSize;
二、系统层面修改
相比于在Launcher层面进行修改的局限性,在系统层修改可以在安装解析应用的时候就把对应的应用图标所替换掉,无疑是最优解。
Android11之前的修改方式
以下示例基于Android7代码:
1、frameworks/base/core/java/android/content/pm/PackageParser.java
com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
ai.descriptionRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
+ //add
+ String pkg2 = pkgName;
+ //android.util.Log.i("hqb","pkg2:"+pkg2);
+
+ if(pkg2.equals("cn.kuwo.kwmusichd")){
+ ai.icon = R.drawable.bs_kwmusichd;
+ }else if(pkg2.equals("com.kk.xx.newplayer")){
+ ai.icon = R.drawable.bs_newplayer;
+ }else if(pkg2.equals("com.chaozh.iReaderFree")){
+ ai.icon = R.drawable.bs_ireaderfree;
+ }else if(pkg2.equals("com.xiaobin.ecdict")){
+ ai.icon = R.drawable.bs_ecdict;
+ }
+ //add
if ((flags&PARSE_IS_SYSTEM) != 0) {
if (sa.getBoolean(
@@ -3408,6 +3422,21 @@ public class PackageParser {
outInfo.packageName = owner.packageName;
+ //add
+ String pkg2 = owner.applicationInfo.packageName;
+ android.util.Log.i("11111Tag","pkg2:"+pkg2);
+
+ if(pkg2.equals("cn.kuwo.kwmusichd")){
+ outInfo.icon = R.drawable.bs_kwmusichd;
+ }else if(pkg2.equals("com.kk.xx.newplayer")){
+ outInfo.icon = R.drawable.bs_newplayer;
+ }else if(pkg2.equals("com.chaozh.iReaderFree")){
+ outInfo.icon = R.drawable.bs_ireaderfree;
+ }else if(pkg2.equals("com.xiaobin.ecdict")){
+ outInfo.icon = R.drawable.bs_ecdict;
+ }
+ //add
+
return true;
}
@@ -3571,7 +3600,7 @@ public class PackageParser {
a.info.screenOrientation = sa.getInt(
R.styleable.AndroidManifestActivity_screenOrientation,
SCREEN_ORIENTATION_UNSPECIFIED);
-
+ a.info.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
final boolean appDefault = (owner.applicationInfo.privateFlags
& PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0;
@@ -3723,6 +3752,21 @@ public class PackageParser {
a.info.exported = a.intents.size() > 0;
}
+ //add
+ String pkg2 = owner.applicationInfo.packageName;
+ android.util.Log.i("hqb","pkg2:"+pkg2);
+
+ if(pkg2.equals("cn.kuwo.kwmusichd")){
+ a.info.icon = R.drawable.bs_kwmusichd;
+ }else if(pkg2.equals("com.kk.xx.newplayer")){
+ a.info.icon = R.drawable.bs_newplayer;
+ }else if(pkg2.equals("com.chaozh.iReaderFree")){
+ a.info.icon = R.drawable.bs_ireaderfree;
+ }else if(pkg2.equals("com.xiaobin.ecdict")){
+ a.info.icon = R.drawable.bs_ecdict;
+ }
+ //add
+
return a;
}
2、frameworks/base/core/res/res/values/symbols.xml
+ <java-symbol type="drawable" name="bs_newplayer" />
+ <java-symbol type="drawable" name="bs_ireaderfree" />
+ <java-symbol type="drawable" name="bs_kwmusichd" />
+ <java-symbol type="drawable" name="bs_ecdict" />
3、frameworks/base/core/res/res/drawable添加图标
以下示例基于Android9代码:
1、frameworks/base/core/java/android/content/pm/PackageParser.java
private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
String[] outError, String tag, TypedArray sa, boolean nameRequired,
int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
// This case can only happen in unit tests where we sometimes need to create fakes
// of various package parser data structures.
if (sa == null) {
outError[0] = tag + " does not contain any attributes";
return false;
}
String name = sa.getNonConfigurationString(nameRes, 0);
if (name == null) {
if (nameRequired) {
outError[0] = tag + " does not specify android:name";
return false;
}
} else {
outInfo.name
= buildClassName(owner.applicationInfo.packageName, name, outError);
if (outInfo.name == null) {
return false;
}
}
final boolean useRoundIcon =
Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
if (roundIconVal != 0) {
outInfo.icon = roundIconVal;
outInfo.nonLocalizedLabel = null;
} else {
int iconVal = sa.getResourceId(iconRes, 0);
if (iconVal != 0) {
outInfo.icon = iconVal;
outInfo.nonLocalizedLabel = null;
}
}
int logoVal = sa.getResourceId(logoRes, 0);
if (logoVal != 0) {
outInfo.logo = logoVal;
}
int bannerVal = sa.getResourceId(bannerRes, 0);
if (bannerVal != 0) {
outInfo.banner = bannerVal;
}
TypedValue v = sa.peekValue(labelRes);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
outInfo.nonLocalizedLabel = v.coerceToString();
}
//add
String applabel= sa.getNonConfigurationString(labelRes, 0);
String pkg1 = outInfo.packageName;
String pkg2 = owner.applicationInfo.packageName;
android.util.Log.i("11111Tag","outInfo name:"+outInfo.name);
android.util.Log.i("11111Tag","pkg2:"+pkg2);
android.util.Log.i("11111Tag","tag:"+tag);
if(pkg2.equals("com.google.android.inputmethod.latin")){
outInfo.icon = R.drawable.cus_inputmethod;
}else if(pkg2.equals("com.apple.android.music")){
outInfo.icon = R.drawable.cus_apple;
}else if(pkg2.equals("com.spotify.music")){
outInfo.icon = R.drawable.cus_spotify;
}else if(pkg2.equals("com.audible.application")){
outInfo.icon = R.drawable.cus_audible;
}else if(pkg2.equals("com.amazon.mp3")){
outInfo.icon = R.drawable.cus_amazon;
}else if(pkg2.equals("deezer.android.app")){
outInfo.icon = R.drawable.cus_deezer;
}else if(pkg2.equals("com.android.chrome")){
outInfo.icon = R.drawable.cus_chrome;
}else if(pkg2.equals("com.android.vending")){
outInfo.icon = R.drawable.cus_vending;
}else if(pkg2.equals("com.hiby.music")){
outInfo.icon = R.drawable.cus_hiby;
}/* else if(pkg2.equals("com.mxtech.videoplayer.pro")){
outInfo.icon = R.drawable.cus_mxtech;
} */
//add
outInfo.packageName = owner.packageName;
return true;
}
2、在frameworks/base/core/res/res/drawable/下面添加所要替换的图标资源
3、frameworks/base/core/res/res/values/symbols.xml中添加图标symbols才能找到资源
<java-symbol type="drawable" name="ic_account_circle" />
<java-symbol type="drawable" name="cus_amazon" />
<java-symbol type="drawable" name="cus_apple" />
<java-symbol type="drawable" name="cus_audible" />
<java-symbol type="drawable" name="cus_chrome" />
<java-symbol type="drawable" name="cus_deezer" />
<java-symbol type="drawable" name="cus_hiby" />
<java-symbol type="drawable" name="cus_inputmethod" />
Android11之后的修改方式
代码路径:frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
具体是在 parseBaseAppBasicFlags(pkg, sa);中解析的:
private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
int targetSdk = pkg.getTargetSdkVersion();
//@formatter:off
// CHECKSTYLE:off
pkg
// Default true
.setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
.setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
.setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
.setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
.setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
.setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
.setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
// Default false
.setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
.setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
....
.setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
- .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))// 去掉之前的设置icon的方法
.setLogo(resId(R.styleable.AndroidManifestApplication_logo, sa))
.setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
.setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
.setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
// Strings
.setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
.setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
.setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa))
.setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa))
// Non-Config String
.setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
// add core start
String pkgName = pkg.getPackageName();
android.util.Log.d("hqb","pkgname="+pkgName);
if(!TextUtils.isEmpty(pkgName)&&pkgName.equals("com.android.settings")){
pkg.setIconRes(com.android.internal.R.mipmap.sym_def_app_icon);
}else if(!TextUtils.isEmpty(pkgName)&&pkgName.equals("com.tencent.android.qqdownloader")){
pkg.setIconRes(com.android.internal.R.mipmap.sym_def_app_icon);
}else if(!TextUtils.isEmpty(pkgName)&&pkgName.equals("com.mxtech.videoplayer.pro")){
pkg.setIconRes(com.android.internal.R.mipmap.sym_def_app_icon);
}else{
pkg.setIconRes(com.android.internal.R.mipmap.sym_def_app_icon);
}
//add core end
// CHECKSTYLE:on
//@formatter:on
}
android13修改第三方应用图标
1、涉及到修改的文件为:
/frameworks/base/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
/frameworks/base/core/res/res/values/symbols.xml
2、/frameworks/base/core/res/res/下添加资源并声明
<java-symbol type="drawable" name="ic_account_circle" />
<java-symbol type="drawable" name="cus_amazon" />
<java-symbol type="drawable" name="cus_apple" />
<java-symbol type="drawable" name="cus_audible" />
<java-symbol type="drawable" name="cus_chrome" />
<java-symbol type="drawable" name="cus_deezer" />
<java-symbol type="drawable" name="cus_hiby" />
<java-symbol type="drawable" name="cus_inputmethod" />
3、解析Application时替换图标
在ParsingPackageUtils文件中的parseBaseAppBasicFlags方法添加判断包名,然后替换图标的代码。
private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
......
......
......
int resIcon = getDefaultIcon(pkg.getPackageName());
if (resIcon != 0) {
pkg.setIconRes(resIcon);
}
}
public static int getDefaultIcon(String packageName) {
int resId = 0;
switch (packageName) {
case "com.sohu.inputmethod.sogou":
resId = com.android.internal.R.mipmap.ic_launcher_sogou;
break;
}
return resId;
}
4、解析Activity时替换图标
有些应用的launcher activity也声明了icon的话,就需要在ParsedActivityUtils文件中的parseActivityOrAlias方法也添加上上述替换图标的代码。通过在循环中的intentFilter判断包含ACTION_MAIN,CATEGORY_LAUNCHER字段,且设置了icon的话,去替换图标。
@NonNull
private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivityImpl activity,
ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,
TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,
ParseInput input, int parentActivityNameAttr, int permissionAttr,
int exportedAttr) throws IOException, XmlPullParserException {
......
......
......
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final ParseResult result;
if (parser.getName().equals("intent-filter")) {
ParseResult<ParsedIntentInfoImpl> intentResult = parseIntentFilter(pkg, activity,
!isReceiver, visibleToEphemeral, resources, parser, input);
if (intentResult.isSuccess()) {
ParsedIntentInfoImpl intentInfo = intentResult.getResult();
if (intentInfo != null) {
IntentFilter intentFilter = intentInfo.getIntentFilter();
activity.setOrder(Math.max(intentFilter.getOrder(), activity.getOrder()));
activity.addIntent(intentInfo);
if (LOG_UNSAFE_BROADCASTS && isReceiver
&& pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
int actionCount = intentFilter.countActions();
for (int i = 0; i < actionCount; i++) {
final String action = intentFilter.getAction(i);
if (action == null || !action.startsWith("android.")) {
continue;
}
if (!SAFE_BROADCASTS.contains(action)) {
Slog.w(TAG,
"Broadcast " + action + " may never be delivered to "
+ pkg.getPackageName() + " as requested at: "
+ parser.getPositionDescription());
}
}
}
+ if (intentFilter.hasAction(ACTION_MAIN)
+ && intentFilter.hasCategory(CATEGORY_LAUNCHER)
+ && activity.getIcon() != 0) {
+ int resIcon = ParsingPackageUtils.getDefaultIcon(pkg.getPackageName());
+ if (resIcon != 0) {
+ activity.setIcon(resIcon);
+ }
+ }
}
}
result = intentResult;
} else if (parser.getName().equals("meta-data")) {
result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input);
} else if (parser.getName().equals("property")) {
result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input);
} else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) {
ParseResult<ParsedIntentInfoImpl> intentResult = parseIntentFilter(pkg, activity,
true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral,
resources, parser, input);
if (intentResult.isSuccess()) {
ParsedIntentInfoImpl intent = intentResult.getResult();
if (intent != null) {
pkg.addPreferredActivityFilter(activity.getClassName(), intent);
}
}
result = intentResult;
} else if (!isReceiver && !isAlias && parser.getName().equals("layout")) {
ParseResult<ActivityInfo.WindowLayout> layoutResult =
parseActivityWindowLayout(resources, parser, input);
if (layoutResult.isSuccess()) {
activity.setWindowLayout(layoutResult.getResult());
}
result = layoutResult;
} else {
result = ParsingUtils.unknownTag(tag, pkg, parser, input);
}
if (result.isError()) {
return input.error(result);
}
}
......
......
......
}
添加应用图标背景
Android11之前
代码路径:Launcher3\src\com\android\launcher3\graphics\LauncherIcons.java
createIconBitmap下面
return getRoundedBitmap(bitmap);
}
public static Bitmap getRoundedBitmap(Bitmap mBitmap){
//Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);
//创建与原始位图大小相同的画布位图ᄡᄡᄑ따샤ᅫ콰ᄐ
/* Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
//初始化画布
Canvas mCanvas = new Canvas(bgBitmap);
Paint mPaint = new Paint();
Rect mRect = new Rect(5, 5, mBitmap.getWidth()-5, mBitmap.getHeight()-5);
RectF mRectF = new RectF(mRect);
//设置圆角半径
float roundPx = 480;
mPaint.setAntiAlias(true);
//绘制圆角矩形
mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint);
//设置图像的叠加模式, 此处模式选择可参考后面的规则
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图像
mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint); */
return addBorderToImage(mBitmap);
}
private static Bitmap addBorderToImage(Bitmap src) {
Bitmap output = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.iconback).copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(output);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
//paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
android.util.Log.d("hqb1"," output.getHeight()="+output.getHeight()+" output.getWidth()="+output.getWidth());
Rect dstRect = new Rect(0,0,output.getWidth(),output.getHeight());
canvas.drawBitmap(src, null, dstRect, paint);
return output;
}
Android11之后
在Android13代码中BaseIconFactory.java从Launcher中移到了frameworks/libs/下面,所以修改这个地方所有的图标后面都会有背景。
frameworks/libs/systemui/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Bundle;
import android.graphics.BitmapFactory;
....
....
private final Rect mOldBounds = new Rect();
private final SparseBooleanArray mIsUserBadged = new SparseBooleanArray();
- protected final Context mContext;
+ protected static Context mContext;
private final Canvas mCanvas;
private final PackageManager mPm;
private final ColorExtractor mColorExtractor;
....
....
private Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size,
Bitmap.Config config) {
Bitmap bitmap = Bitmap.createBitmap(size, size, config);
if (icon == null) {
return bitmap;
}
....
....
....
//return bitmap;
return addBorderToImage(bitmap);
}
private static Bitmap addBorderToImage(Bitmap src) {
Bitmap output = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.iconback).copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(output);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
//paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
android.util.Log.d("hqb1"," output.getHeight()="+output.getHeight()+" output.getWidth()="+output.getWidth());
Rect dstRect = new Rect(5,5,output.getWidth()-5,output.getHeight()-5);
canvas.drawBitmap(src, null, dstRect, paint);
return output;
}
移除图标白边,图标铺满
Android11之前
代码路径:packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherIcons.java
private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, int iconAppTargetSdk,
RectF outIconBounds, float[] outScale) {
float scale = 1f;
//hqingbin 2023 Remove the icon white edge begin
/* if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
boolean[] outShape = new boolean[1];
if (mWrapperIcon == null) {
mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
.mutate();
}
AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
dr.setBounds(0, 0, 1, 1);
scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
if (Utilities.ATLEAST_OREO && !outShape[0] && !(icon instanceof AdaptiveIconDrawable)) {
FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
fsd.setDrawable(icon);
fsd.setScale(scale);
icon = dr;
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
}
} else {
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
} */
//hqingbin 2023 Remove the icon white edge end
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
outScale[0] = scale;
return icon;
}
Android11之后
代码路径:frameworks/libs/systemui/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
private Drawable normalizeAndWrapToAdaptiveIcon(@NonNull Drawable icon,
boolean shrinkNonAdaptiveIcons, RectF outIconBounds, float[] outScale) {
if (icon == null) {
return null;
}
float scale = 1f;
/* if (shrinkNonAdaptiveIcons && ATLEAST_OREO) {
if (mWrapperIcon == null) {
mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
.mutate();
}
AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
dr.setBounds(0, 0, 1, 1);
boolean[] outShape = new boolean[1];
scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) {
FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
fsd.setDrawable(icon);
fsd.setScale(scale);
icon = dr;
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
}
} else { */
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
//}
outScale[0] = scale;
return icon;
}