Android8.1 Launcher3中应用icon的替换

时间:2025-01-27 14:30:48

客户给了一套应用icon图片,要求替换当前应用的icon,实现如下.

将要替换的应用包名存放在字符串数组中:

<string-array name="icon_package" translatable="false">
            <!-- 相机 -->
	    <item>.camera2</item>
	    <!-- 浏览器 -->
	    <item>,</item>
	    <!-- 联系人 -->
	    <item></item>
	    <!-- 电话 -->
	    <item></item>
	    <!-- 图库 -->
	    <item>.gallery3d</item>
	    <!-- 音乐 -->
	    <item></item>
	    <!-- 设置 -->
	    <item></item>
	    <!-- 应用商店 -->
	    <item></item>
 </string-array>

将客户提供的应用icon的名称也存放在字符串数组中,注意应用icon图片名称在数组中位置要与包名数组中应用包名的位置

相对应,如下:

<string-array name="icon_package" translatable="false">
	    <!-- 相机 -->
	    <item>theme_camera.png</item>
	    <!-- 浏览器 -->
	    <item>theme_browser.png</item>
	    <!-- 联系人 -->
	    <item>theme_contacts.png</item>
	    <!-- 电话 -->
	    <item>theme_phone.png</item>
	    <!-- 图库 -->
	    <item>theme_gallery.png</item>
	    <!-- 音乐 -->
	    <item>theme_music.png</item>
	    <!-- 设置 -->
	    <item>theme_settings.png</item>
	    <!-- 应用商店 -->
	    <item>theme_appstore.png</item>
 </string-array>
Launcher3获取应用图标时都会经过一个类,

代码路径:packages/apps/Launcher3/src/com/android/launcher3/

在中找到函数:cacheLocked

函数中有下面几行代码:

 = (
                   getFullResIcon(info), (), mContext,
                   ().getApplicationInfo().targetSdkVersion);

没错这里就是设置应用icon的地方了,下面就需要我们在这里替换客户提供的应用icon了。

首先获取存放包名的字符串数组:

private String getIconPackage(int i){
	String[] arr = ().getStringArray(.icon_package);

	return arr[i];
}

再通过存放icon图片名称的数组得到对应图片的资源ID:

private int getIconId(int i){

        String[] imageNameArr = ().getStringArray(.icon_image);
	String imageName = null;
	if(!(imageNameArr[i])){
             //获取图片的名称,去掉后缀
             imageName = imageNameArr[i].substring(0, imageNameArr[i].indexOf("."));
	}
        //通过图片名称获取图片的资源ID
        int resId = ().getIdentifier(imageName, "drawable" , ()); 
	return resId;
}

然后再实现替换应用icon的功能:

private void setAppIconTheme(ComponentName componentName, 
				Provider<LauncherActivityInfo> infoProvider, 
				LauncherActivityInfo info, 
				CacheEntry entry){
	String[] arr = ().getStringArray(.icon_package);							
	//通过for循环取数组中的包名和系统应用的包名对比,匹配上则替换该应用的icon,替换成功就结束函数					
	for (int i = 0; i < ; i++) {
		("lp","()="+());
                //这里判断字符串包含而不是相等,这样的好处我们可以在包名数组中的单个item中存放同类功能的不同应用,
                //比如邮箱存放如下:
                //<!-- 邮箱 -->
                //<item>,</item>
                if(getIconPackage(i).contains(())){
			("lp","packageName("+ i +")="+getIconPackage(i));
			 = ((),getIconId(i));
			return;
		}
	}
        //for循环没匹配到,则执行默认代码
	 = (
                   getFullResIcon(info), (), mContext,
                   ().getApplicationInfo().targetSdkVersion);
}

接下来就用函数setAppIconTheme替换系统默认的代码:

protected CacheEntry cacheLocked(
            @NonNull ComponentName componentName,
            @NonNull Provider<LauncherActivityInfo> infoProvider,
            UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {

        ........... 
        ........... 
        //此处省略 
        ........... 
        ........... 
        //用函数setAppIconTheme替换系统默认的代码: 
        if (().getBoolean(.config_app_icon_theme)) { 
        	setAppIconTheme(componentName, infoProvider, info, entry);
        }else { 
        	 = ( getFullResIcon(info), 
        								(), mContext, 
        								().getApplicationInfo().targetSdkVersion);
        } 
        ...........
        ...........
        //此处省略
        ...........
        ...........
        return entry;
}

能力有限,不当之处请多多指正!!