zoukankan      html  css  js  c++  java
  • Android 类似未读短信图标显示数字效果的分析

    之前一直以为是应用本身在对图标进行修改,看了源码之后发现其实主要的工作并不是应用自己完成的,主要的工作在是launcher里面完成的.

    关于系统里面类似未读短信的具体处理流程如下,
    原理
    一个应用要实现这个效果,就要在自己有未读的消息的时候发送一个广播告诉系统我有未处理的事件了(例如:短信,电话和邮件等),同时将相关的信息进行保存,比如应用的名称(这里指的是ComponentName)和未处理事件的数量.系统将提升用户有待处理的事件交给Launcher去处理,launcher会接收到对应的广播,不是随便一个应用都有这个待遇的,launcher接到广播之后会先解析数据,看当前的应用有没有这个待遇也就是是否支持显示这个待处理事件的通知.如果通过launcher就会调用相关方法去重绘应用的icon.
    效果图: 实现过程分析
    Intent.java(系统增加3个常量)
    frameworks/base/core/java/android/content/Intent.java
    Java代码  收藏代码
    1. //状态    
    2. public static final String MTK_ACTION_UNREAD_CHANGED = "com.mediatek.action.UNREAD_CHANGED"; 
    3. //应用名称     
    4. public static final String MTK_EXTRA_UNREAD_COMPONENT = "com.mediatek.intent.extra.UNREAD_COMPONENT"; 
    5. //数量 
    6. public static final String MTK_EXTRA_UNREAD_NUMBER = "com.mediatek.intent.extra.UNREAD_NUMBER"; 
    7.   
    系统里面有这个功能几个应用相关的代码路径
    日历 packages/apps/Calendar/src/com/mediatek/calendar/MTKUtils.java
    邮件 :packages/apps/Email/src/com/android/email/NotificationController.java
    电话 :packages/providers/ContactsProvider/src/com/android/providers/contacts/CallLogProvider.java 
    短信 :packages/providers/TelephonyProvider/src/com/android/providers/telephony/MmsSmsProvider.java
     
    这里以电话为例:
    假设当前有人打电话进来,系统会保存改记录到数据库,根据事件是否已经处理来判断是否发送广播
     
    CallLogProvider.java(发送有待处理事件的广播)
    packages/providers/ContactsProvider/src/com/android/providers/contacts/CallLogProvider.java
    Java代码  收藏代码
    1. /** M: send new Calls broadcast to luancher to update unread icon @{ */ 
    2.     public static final void notifyNewCallsCount(SQLiteDatabase db, Context context) { 
    3.         Cursor c = null; 
    4.        ….. 
    5.         //send count=0 to clear the unread icon 
    6.         if (newCallsCount >= 0) { //有新的来电数量 
    7.             Intent newIntent = new Intent(Intent.MTK_ACTION_UNREAD_CHANGED); 
    8.             newIntent.putExtra(Intent.MTK_EXTRA_UNREAD_NUMBER, newCallsCount); 
    9.             newIntent.putExtra(Intent.MTK_EXTRA_UNREAD_COMPONENT, new ComponentName(Constants.CONTACTS_PACKAGE, 
    10.                     Constants.CONTACTS_DIALTACTS_ACTIVITY)); 
    11.             context.sendBroadcast(newIntent); //发送对应的广播 
    12.             android.provider.Settings.System.putInt(context.getContentResolver(), Constants.CONTACTS_UNREAD_KEY, Integer 
    13.                     .valueOf(newCallsCount)); 
    14.         } 
    15.     } 
    MTKUnreadLoader.java(Launcher接收到应用发送的广播,进行判断改应用是否可以显示有未处理事件的图标)
    packages/apps/Launcher2/src/com/android/launcher2/MTKUnreadLoader.java
    Java代码  收藏代码
    1. public void onReceive(final Context context, final Intent intent) { 
    2.         final String action = intent.getAction(); 
    3.             //过滤广播 
    4.         if (Intent.MTK_ACTION_UNREAD_CHANGED.equals(action)) { 
    5.             final ComponentName componentName = (ComponentName) intent.getExtra(Intent.MTK_EXTRA_UNREAD_COMPONENT); 
    6.             final int unreadNum = intent.getIntExtra(Intent.MTK_EXTRA_UNREAD_NUMBER, -1); 
    7.  
    8.             if (mCallbacks != null && componentName != null && unreadNum != -1) { 
    9.                 //判断是否支持该功能 
    10.                 final int index = supportUnreadFeature(componentName); 
    11.                 if (index >= 0) { //支持 
    12.                     boolean ret = setUnreadNumberAt(index, unreadNum); 
    13.                     if (ret) { 
    14.                         final UnreadCallbacks callbacks = mCallbacks.get(); 
    15.                         if (callbacks != null) { 
    16.                             callbacks.bindComponentUnreadChanged(componentName, unreadNum); 
    17.                         } 
    18.                     ......... 
    19.     } 
    LauncherApplication.java(Launcher注册对应的广播接收器)
    packages/apps/Launcher2/src/com/android/launcher2/LauncherApplication.java
    Java代码  收藏代码
    1. public void onCreate() { 
    2.        ........ 
    3.         /// M: register unread broadcast. 
    4.         if (FeatureOption.MTK_LAUNCHER_UNREAD_SUPPORT) { 
    5.             mUnreadLoader = new MTKUnreadLoader(getApplicationContext()); 
    6.             // Register unread change broadcast. 
    7.             filter = new IntentFilter(); 
    8.             filter.addAction(Intent.MTK_ACTION_UNREAD_CHANGED); 
    9.             registerReceiver(mUnreadLoader, filter); //注册对应的广播接收器 
    10.         } 
    11.        .............. 
    12.     } 
    MTKUnreadLoader.java(处理应用的图标显示未处理事件的数字)
    packages/apps/Launcher2/src/com/android/launcher2/MTKUnreadLoader.java
    Java代码  收藏代码
    1. static void drawUnreadEventIfNeed(Canvas canvas, View icon) { 
    2.         ItemInfo info = (ItemInfo)icon.getTag(); 
    3.         if (info != null && info.unreadNum > 0) { //判断未处理事件数量 
    4.             Resources res = icon.getContext().getResources(); 
    5.            .......... 
    6.             if (info.unreadNum > Launcher.MAX_UNREAD_COUNT) { 
    7.                 unreadTextNumber = String.valueOf(Launcher.MAX_UNREAD_COUNT); 
    8.                 unreadTextPlusPaint.getTextBounds(unreadTextPlus, 0, unreadTextPlus.length(), unreadTextPlusBounds); 
    9.             } else { 
    10.                 unreadTextNumber = String.valueOf(info.unreadNum); 
    11.             } 
    12.             unreadTextNumberPaint.getTextBounds(unreadTextNumber, 0, unreadTextNumber.length(), unreadTextNumberBounds); 
    13.             int textHeight = unreadTextNumberBounds.height(); 
    14.             int textWidth = unreadTextNumberBounds.width() + unreadTextPlusBounds.width(); 
    15.  
    16.             // 数字的背景图 
    17.             NinePatchDrawable unreadBgNinePatchDrawable = (NinePatchDrawable)res.getDrawable(R.drawable.ic_newevents_numberindication); 
    18.            ......... 
    19.             Rect unreadBgBounds = new Rect(0, 0, unreadBgWidth, unreadBgHeight); 
    20.             unreadBgNinePatchDrawable.setBounds(unreadBgBounds); 
    21.  
    22.             int unreadMarginTop = 0; 
    23.             int unreadMarginRight = 0; 
    24.             if (info instanceof ShortcutInfo) { //workspace 里面的快捷方式 
    25.                 if (info.container == (long)LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 
    26.                     unreadMarginTop = (int)res.getDimension(R.dimen.hotseat_unread_margin_top); 
    27.                     unreadMarginRight = (int)res.getDimension(R.dimen.hotseat_unread_margin_right); 
    28.                 } else if (info.container == (long)LauncherSettings.Favorites.CONTAINER_DESKTOP) { 
    29.                     unreadMarginTop = (int)res.getDimension(R.dimen.workspace_unread_margin_top); 
    30.                     unreadMarginRight = (int)res.getDimension(R.dimen.workspace_unread_margin_right); 
    31.                 } else { 
    32.                     unreadMarginTop = (int)res.getDimension(R.dimen.folder_unread_margin_top); 
    33.                     unreadMarginRight = (int)res.getDimension(R.dimen.folder_unread_margin_right); 
    34.                 } 
    35.             } else if (info instanceof FolderInfo) { //文件夹 
    36.                 if (info.container == (long)LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 
    37.                     unreadMarginTop = (int)res.getDimension(R.dimen.hotseat_unread_margin_top); 
    38.                     unreadMarginRight = (int)res.getDimension(R.dimen.hotseat_unread_margin_right); 
    39.                 } else if (info.container == (long)LauncherSettings.Favorites.CONTAINER_DESKTOP) { 
    40.                     unreadMarginTop = (int)res.getDimension(R.dimen.workspace_unread_margin_top); 
    41.                     unreadMarginRight = (int)res.getDimension(R.dimen.workspace_unread_margin_right); 
    42.                 } 
    43.             } 
    44.             else if (info instanceof ApplicationInfo) { //all app 里面的应用icon 
    45.                 unreadMarginTop = (int)res.getDimension(R.dimen.app_list_unread_margin_top); 
    46.                 unreadMarginRight = (int)res.getDimension(R.dimen.app_list_unread_margin_right); 
    47.             } 
    48.  
    49.             int unreadBgPosX = icon.getScrollX() + icon.getWidth() - unreadBgWidth - unreadMarginRight; 
    50.             int unreadBgPosY = icon.getScrollY() + unreadMarginTop; 
    51.  
    52.             canvas.save(); 
    53.             canvas.translate(unreadBgPosX, unreadBgPosY); 
    54.  
    55.             unreadBgNinePatchDrawable.draw(canvas); 
    56.  
    57.             /// M: Draw unread text. 
    58.             Paint.FontMetrics fontMetrics = unreadTextNumberPaint.getFontMetrics(); 
    59.             if (info.unreadNum > Launcher.MAX_UNREAD_COUNT) { 
    60.                 canvas.drawText(unreadTextNumber, 
    61.                                 (unreadBgWidth - unreadTextPlusBounds.width()) / 2, 
    62.                                 (unreadBgHeight + textHeight) / 2, 
    63.                                 unreadTextNumberPaint); 
    64.                 canvas.drawText(unreadTextPlus, 
    65.                                 (unreadBgWidth + unreadTextNumberBounds.width()) / 2, 
    66.                                 (unreadBgHeight + textHeight) / 2 + fontMetrics.ascent / 2, 
    67.                                 unreadTextPlusPaint); 
    68.             } else { 
    69.                ..... 
    70.         } 
    71.     } 
    unread_support_shortcuts.xml(配置哪些应用可以显示待处理的事件)
    packages/apps/Launcher2/res/xml/unread_support_shortcuts.xml
    Xml代码  收藏代码
    1. <unreadshortcuts xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
    2. <!--电话--> 
    3.     <shortcut 
    4.         launcher:unreadPackageName="com.android.contacts" 
    5.         launcher:unreadClassName="com.android.contacts.activities.DialtactsActivity" 
    6.         launcher:unreadType="0" 
    7.         launcher:unreadKey="com_android_contacts_mtk_unread" 
    8.      /> 
    9. <!--短信--> 
    10.      <shortcut 
    11.         launcher:unreadPackageName="com.android.mms" 
    12.         launcher:unreadClassName="com.android.mms.ui.BootActivity" 
    13.         launcher:unreadType="0" 
    14.         launcher:unreadKey="com_android_mms_mtk_unread" 
    15.      /> 
    16. <!--邮件--> 
    17.      <shortcut 
    18.         launcher:unreadPackageName="com.android.email" 
    19.         launcher:unreadClassName="com.android.email.activity.Welcome" 
    20.         launcher:unreadType="0" 
    21.         launcher:unreadKey="com_android_email_mtk_unread" 
    22.      /> 
    23.     ................ 
    24. </unreadshortcuts
  • 相关阅读:
    js localtion.href 数据传输
    java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver 找不到jar包的问题,路径问题
    java 深度拷贝 复制 深度复制
    解决java在对MySQL插入数据时出现乱码问题
    python最大最小距离算法贴近度评价法
    java 连接数据库报错:Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '
    java map 转 json 自编封装
    java 连接MySQL的代码
    在前端发起ajax遇到问题
    java map转json servlet response
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4469108.html
Copyright © 2011-2022 走看看