近期由于moto的项目需要适配,根据原生机制实现日历的动态图标,所以研究了一下:
packages/apps/Launcher3/src/com/android/launcher3/DynamicIconProvider.java
Launcher的DaynamicIconProvider.java文件夹中有相关的代码,我们来看,google是如何实现日历动态图标的。
在构造函数中注册了和Date变化相关的监听器
/** 61 * invoked by IconProvider#loadByName 62 * @param context context 63 */ 64 public DynamicIconProvider(Context context) { 65 IntentFilter filter = new IntentFilter(Intent.ACTION_TIME_CHANGED); 66 filter.addAction("android.intent.action.TIME_SET"); 67 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 68 69 context.registerReceiver(new DateTimeChangedReceiver(), filter); 70 mPackageManager = context.getPackageManager(); 71 }
当日期或者timezone产生变化后,回调getIcon方法
90 @Override 91 public Drawable getIcon(LauncherActivityInfo info, int iconDpi, boolean flattenDrawable) { 92 String packageName = info.getApplicationInfo().packageName; 93 Drawable icon = null; 94 if (isCalendarSupportedDynamicIcon(packageName)) {//判断是否支持 95 try { 96 Bundle bundle = mPackageManager.getActivityInfo(info.getComponentName(), 97 PackageManager.GET_META_DATA).metaData;获取calendar AndroidManifest中metadata 标签相关的信息 //获取日历apk resources 98 Resources resources = mPackageManager.getResourcesForApplication(packageName); //这个方法应该是关键 99 int iconResId = getCalendarIconResource(bundle, resources); 100 if (iconResId != 0) { 101 icon = resources.getDrawableForDensity(iconResId, iconDpi, null); 102 } 103 } catch (PackageManager.NameNotFoundException e) { 105 } 106 } 114 return icon; 115 } 116
接下来来看我们猜测的关键方法 getCalendarIconResource(bundle,resources)这个方法
private int getCalendarIconResource(Bundle bundle, Resources resources) { 171 172 boolean useRoundIcon = getIsSystemUseRoundIcon(); //提供了2套资源,一个是圆形的一个非圆形的,根据这个条件取不同的资源 173 int iconArrayResId = bundle.getInt(useRoundIcon ? 174 GMS_CALENDAR_RES_ARRAY_ROUND : GMS_CALENDAR_RES_ARRAY_REGULAR, 0); 175 if (iconArrayResId == 0) { 176 return 0; 177 } 178 179 try{ //先是获取Array,之后根据日历的日期获取对应的资源 180 return resources.obtainTypedArray(iconArrayResId).getResourceId( 181 generateResourceIndexWithCalendarDate(), 0); 182 } catch (Resources.NotFoundException e) { 183 if (DBG) loge("getCalendarIconResource -> Resources.NotFoundException", e); 184 } 185 return 0; 186 }
至此我们大概明白了,google实现动态图标的原理,主要是跨包获取日历的资源,这个资源可能定义在manifest中的Metadata,然后根据日期获取对应的图片资源。
我们反编译GMS 的日历,找一下
这两个key的名字和Launcher中定义的DynamicIconProvider.java 两个key可以对应起来,看来就是两个array就是日历提供的动态图标了。
- @drawable/logo_calendar_01_adaptive
- @drawable/logo_calendar_02_adaptive
- @drawable/logo_calendar_03_adaptive
- @drawable/logo_calendar_04_adaptive
- @drawable/logo_calendar_05_adaptive
- @drawable/logo_calendar_06_adaptive
- @drawable/logo_calendar_07_adaptive
- @drawable/logo_calendar_08_adaptive
- @drawable/logo_calendar_09_adaptive
- @drawable/logo_calendar_10_adaptive
- @drawable/logo_calendar_11_adaptive
- @drawable/logo_calendar_12_adaptive
- @drawable/logo_calendar_13_adaptive
- @drawable/logo_calendar_14_adaptive
- @drawable/logo_calendar_15_adaptive
- @drawable/logo_calendar_16_adaptive
- @drawable/logo_calendar_17_adaptive
- @drawable/logo_calendar_18_adaptive
- @drawable/logo_calendar_19_adaptive
- @drawable/logo_calendar_20_adaptive
- @drawable/logo_calendar_21_adaptive
- @drawable/logo_calendar_22_adaptive
- @drawable/logo_calendar_23_adaptive
- @drawable/logo_calendar_24_adaptive
- @drawable/logo_calendar_25_adaptive
- @drawable/logo_calendar_26_adaptive
- @drawable/logo_calendar_27_adaptive
- @drawable/logo_calendar_28_adaptive
- @drawable/logo_calendar_29_adaptive
- @drawable/logo_calendar_30_adaptive
- @drawable/logo_calendar_31_adaptive
找到后是01-31的drawbale资源,每一个drawable都是按照google新的静态图标的规范提供的,有背景和前景两个layer
至此就清楚了,只要请GUI 按照google提供的背景,以及1-31的资源图就可以了。:)