- 概述
Android系统的Launcher改造在国内算是一个不算很低频的需求,尤其是相当多的三方硬件设备以及部分手机厂商的个性化ROM等,受限于国内整体的开源环境,网上能找到相关的开发资源并不多,最近公司有相关业务需求的开发,就自己涉及到的改造点作一些分享。
图标替换的方案可能不止一种,我这边尝试过的有改BaseIconCache的cacheLocked方法和改BubbleTextView的applyIconAndLable方法两种,但是前者的问题是假使设备本来没有该包名app,新安装的话,图标不会被替换,所以这里主要讲后一种方式。涉及到的改动点如下:
-
替换定制图标资源
-
解决替换图标比原图标大一圈问题
-
裁剪图标圆角
2. 涉及到的类及接口等
在LtLauncherIconUtils方法中维护对应的包名数组和图标资源数组;在BubbleTextView的applyIconAndLabel方法中筛选替换对应的图标(这里注意一下,Android10版本的Launcher3把图标相关独立成一个库了iconloaderlib,对应的图标资源要放到这里);在BaseIconFactory中调整缩放比例。
com.android.launcher3.icons.LtLauncherIconUtils
com.android.launcher3.BubbleTextView
com.android.launcher3.icons.BaseIconFactory
3. Show the code
-
在LtLauncherIconUtils类中维护两个数组
LtLauncherIconUtils.java
public class LtLauncherIconUtils { private static final String TAG = LtLauncherIconUtils.class.getSimpleName(); private static final String[] PACKAGE_NAMES = { "com.android.settings", "com.android.browser", "com.android.calendar", "com.android.contacts", "com.android.deskclock", "com.android.dialer", "com.android.gallery", "com.android.mms", "com.android.soundrecorder", "com.custom.aaa", "com.custom.bbb", "com.custom.ccc", "com.custom.ddd", "com.custom.eee", "com.custom.fff" }; /** * PACKAGE_ICONS */ private static final int[] PACKAGE_ICONS = { R.drawable.icon_settings, R.drawable.icon_browser, R.drawable.icon_calendar, R.drawable.icon_contact, R.drawable.icon_clock, R.drawable.icon_call, R.drawable.icon_gallery, R.drawable.icon_msg, R.drawable.icon_record, R.drawable.icon_aaa, R.mipmap.ic_bbb, R.drawable.icon_ccc, R.drawable.icon_ddd, R.drawable.icon_eee, R.drawable.icon_fff }; public static Bitmap getIconBitmap(Context context, String packageName) { int i = Arrays.asList(PACKAGE_NAMES).indexOf(packageName); if (i != -1){ return BitmapFactory.decodeResource(context.getResources(),PACKAGE_ICONS[i]); }else{ return null; } } }
-
修改BubbleTextView的applyIconAndLabel方法,添加替换图标列表的过滤逻辑。
BubbleTextView.java
private void applyIconAndLabel(ItemInfoWithIcon info) { //====修改start==== //替换图标,可保证用户新安装的APP也被替换 if (info.getIntent() != null && info.getIntent().getComponent() != null){ // && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { String pkg = info.getIntent().getComponent().getPackageName(); LauncherIcons li = LauncherIcons.obtain(getContext()); Bitmap bp = LtLauncherIconUtils.getIconBitmap(getContext(), pkg); if (null != bp) { info.bitmap = li.createIconBitmap(bp); } } //====修改end==== FastBitmapDrawable iconDrawable = newIcon(getContext(), info); mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 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); } }
-
修改BaseIconFactory的createIconBitmap方法中引用的createIconBitmap(icon,scale)方法中的scale数值,以按比例缩放图标,默认值为1f,我这边改成0.8f就刚好。
BaseIconFactory.java
public BitmapInfo createIconBitmap(Bitmap icon) { if (mIconBitmapSize != icon.getWidth() || mIconBitmapSize != icon.getHeight()) { //====修改start==== icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 0.8f); //====修改end==== } return BitmapInfo.of(icon, extractColor(icon)); }
4. 结语
我这边最初的方案是改BaseIconCache的方案,但后来调试时发现如果被替换的APP是新安装的话,图标不会被替换,以上这种修改方式是可以满足的,供参考。