一步步客制化Android桌面(Launcher3)图标

您所在的位置:网站首页 华为怎么创建桌面快捷图标样式 一步步客制化Android桌面(Launcher3)图标

一步步客制化Android桌面(Launcher3)图标

2024-07-16 16:37:12| 来源: 网络整理| 查看: 265

由于最近在负责MTK5.1的Android系统开发,所以本文就以5.1的代码为参考。其它版本虽然会略有不同,但是修改思路是大致相同的。

在市面上很多手机都会对原生桌面进行一些修改,比如把时钟、日历修改成动态显示,或者对整个界面风格进行修改。那么我们就来模仿一下,简单地修改原生应用的图标显示,从而达到修改主题样式的目的。

5.1上的Android桌面,其实也就是Launcher3,位置是 alps\packages\apps\Launcher3。

思路

我先说下核心思路:在Launcher3获取应用图标时都会经过一个类:IconCache.java,具体位置是 alps\packages\apps\Launcher3\src\com\android\launcher3\IconCache.java.

在这个类中有一个关键的方法:cacheLocked

private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info, HashMap labelCache, UserHandleCompat user, boolean usePackageIcon) { ...... }

Launcher3获取应用图标的方法有好几个,但是这些方法最终都会调用cacheLocked获取应用图标,因此,我们主要的切换主题的逻辑就放在这里做好了。

步骤 一:

在IconCache类中定义全局变量:

private int mThemeCode; private List mThemePackageNames; private static final String[] PACKAGE_NAME = { "com.android.fmradio", "com.android.email", "com.android.music", "com.android.gallery3d", "com.android.providers.downloads.ui", "com.android.browser", "com.mediatek.filemanager", "com.android.calculator2", "com.android.calendar", "com.mediatek.camera", "com.android.contacts", "com.android.deskclock", "com.android.dialer", "com.android.mms", "com.android.settings", "com.android.soundrecorder", "com.android.stk", "com.mediatek.notebook" };

其中PACKAGE_NAME中的包名就是要切换图标的应用包名,mThemeCode是每个主题所对应的值,mThemePackageNames是为了方便处理PACKAGE_NAME中的包名的判断的。

二:

在IconCache的构造函数中初始化成员变量:

public IconCache(Context context) { ...... //mikechenmj add SharedPreferences sharedPreferences = mContext .getSharedPreferences("theme_code",Context.MODE_PRIVATE); mThemeCode = sharedPreferences.getInt("theme",0); mThemePackageNames = Arrays.asList(PACKAGE_NAME); //end }

这里通过SharedPreferences来获取mThemeCode的值,不然当手机重启后主题就会被恢复原样了。然后将PACKAGE_NAME转化成一个List赋值给mThemePackageNames。

三:

在cacheLocked方法中修改指定应用的图标。

private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info, HashMap labelCache, UserHandleCompat user, boolean usePackageIcon) { ...... CacheKey cacheKey = new CacheKey(componentName, user); CacheEntry entry = mCache.get(cacheKey); ...... //mikechenmj add if(entry.icon != null) { Bitmap themeBitmap = getThemeBitmap(componentName ,entry.icon.getWidth(),entry.icon.getHeight()); if(themeBitmap != null) { entry.icon = themeBitmap; } } //end return entry; ...... private static class CacheEntry { public Bitmap icon; public CharSequence title; public CharSequence contentDescription; }

在cacheLocked中,通过方法getThemeBitmap获取新的Bitmap,并赋值给entry。getThemeBitmap方法是一个自己编写的获取指定Bitmap的方法。

在IconCache.java中定义需要的方法

public void setThemeCode(int code) { mThemeCode = code; flush(); SharedPreferences sharedPreferences = mContext.getSharedPreferences("theme_code",Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt("theme",mThemeCode); editor.commit(); } private Bitmap getThemeBitmap(ComponentName componentName, int reqWidth, int reqHeight) { + mThemeCode); if (mThemeCode > 0) { String packageName = componentName.getPackageName(); if (mThemePackageNames.contains(packageName)) { StringBuilder identifierName = new StringBuilder(); int resId; if (packageName.equals("com.android.gallery3d") && componentName.getClassName().equals("com.android.camera.CameraLauncher")) { identifierName.append("com_mediatek_camera_theme_").append(mThemeCode); resId = mContext.getResources().getIdentifier(identifierName.toString(), "drawable", mContext.getPackageName()); } else { identifierName.append(packageName.replace(".", "_")) .append("_theme_") .append(mThemeCode); resId = mContext.getResources().getIdentifier(identifierName.toString(), "drawable", mContext.getPackageName()); } if (resId == 0) { return null; } return decodeResource(mContext, resId, reqWidth, reqHeight); } } return null; } public static Bitmap decodeResource(Context context, int resId, int reqWidth, int reqHeight) { Resources resources = context.getResources(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(resources, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeResource(resources, resId); return bitmap; } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }

其中setThemeCode方法是提供给Launcher3的主活动:Launcher.java调用的。 在这个方法中更新了mThemeCode并保存到了SharedPreferences当中,并且清除了缓存,以免被以前的主题影响。

getThemeBitmap方法主要是根据componentName中携带的包名判断是否需要更图标以及合成需要的图标的名称,并通过decodeResource将其解析出来。当mThemeCode不大于0时,代表使用的是默认的风格,所以不往下执行代码。 而图片的命名都是与包名对应的,比如com_android_browser_theme_1.png对应的就是主题值为1,包名为com.android.browser的应用。 除此之外,由于5.1中的相机和图库的包名是同一个,所以判断相机时加上了类名作为判断条件: componentName.getClassName().equals(“com.android.camera.CameraLauncher”)

decodeResource方法主要是通过calculateInSampleSize方法获取到合适的options.inSampleSize值,然后根据这个值将图标的大小调整合适,再解析出来。

IconCache.java修改完了,接下来就是要想办法去选择并传递ThemeCode。我们可以在主活动Launcher中的OverviewMode模式(既长按桌面进入的调整桌面的模式)中添加一个Button来启动一个新的活动,在新活动中选择主题,并把主题的值返回给Launcher,Launcher再调用IconCache的setThemeCode方法把ThemeCode传递给IconCache,然后通知桌面刷新。代码如下:

在res/layout/overview_panel.xml中新加一个Button

......

其中android:drawableTop属性中的@drawable/theme_button是自己定义的一个xml文件,里面定义了按键被按时和平时显示的图片。

在Launcher初始化时初始化新加的Button,并设置按键事件。

View themeButton = findViewById(R.id.themes_button); themeButton.setVisibility(View.VISIBLE); themeButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent intent = new Intent("mikechenmj.android.activity.LAUNCHER_THEME_PICKER"); startActivityForResult(intent,THEME_PICKER_REQUEST_CODE); } }); themeButton.setOnTouchListener(getHapticFeedbackTouchListener());

当点击这个按钮的时候,会启动一个接收 mikechenmj.android.activity.LAUNCHER_THEME_PICKER这个Action的活动,在这个活动中选择主题风格,并且通过类似下面的方法来返回选择的themeCode。

private void returnThemeCode(int theme) { Intent intent = new Intent(); intent.putExtra("theme_code", theme); setResult(RESULT_OK, intent); finish(); }

选择主题的活动的代码不重要就不贴了,反正大致就这个思路。

然后修改Launcher.java的onActivityResult,调用方法handleThemePicker。

@Override protected void onActivityResult( final int requestCode, final int resultCode, final Intent data) { //mikechenmj add handleThemePicker(requestCode,resultCode,data); //end ...... } private void handleThemePicker(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if(requestCode == THEME_PICKER_REQUEST_CODE && resultCode == RESULT_OK) { int themeCode = data.getIntExtra("theme_code", 0); Resources resources = getResources(); WallpaperManager manager = WallpaperManager.getInstance(this); Bitmap wallpager; if(themeCode == 0) { Resources sysRes = Resources.getSystem(); int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android"); wallpager = IconCache.decodeResource(this, resId, resources.getDisplayMetrics().widthPixels, resources.getDisplayMetrics().heightPixels); }else { StringBuilder stringBuilder = new StringBuilder("launcher_theme_wallpaper_"); stringBuilder.append(themeCode); wallpager = IconCache.decodeResource(this, resources.getIdentifier(stringBuilder.toString(), "drawable", getPackageName()), resources.getDisplayMetrics().widthPixels, resources.getDisplayMetrics().heightPixels); } try { manager.setBitmap(wallpager); } catch (IOException e) { e.printStackTrace(); } if (mState != State.WORKSPACE || mWorkspace.isInOverviewMode()) { showWorkspace(true); } mIconCache.setThemeCode(themeCode); mModel.forceReload(); } } }

在handleThemePicker方法中对themeCode进行了判断,如果themeCode等于0,则代表用的是系统默认的风格,所以壁纸设置成系统默认壁纸。 如果themeCode不等于0,则根据themeCode合成对应壁纸的名称并加载出来,然后将其设置成壁纸。这里的壁纸名称也是有要求的,都是launcher_theme_wallpaper_ 然后加上themeCode。

然后通过mIconCache.setThemeCode(themeCode)方法将themeCode传递给IconCache,再调用 mModel.forceReload()方法通知桌面刷新,调用showWorkspace(true)退出OverviewMode模式。就这样,整个客制化流程就完成了。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭