前几天修改MTK8312平台遇到一个bug,就是来电,短信,邮件或者日历有新消息时,桌面图标没有提示有几条信息,方便用户进行查看,其实MTK平台中是有这方面接口定义的,下面就让我们来查看一下源码吧(此案例主要是针对dialer做详细说明,其他应用需要更新的话,只需要定义接口和发送广播即可).
1、MTK中未读消息intent的定义,方便后续发送广播
所在目录:
frameworks\base\core\java\android\content\Intent.java添加相关代码如下:
/** * M: * Broadcast Action: action used for launcher unread number feature. * The broadcat is sent when the unread number of application changes. * @hide */ public static final String MTK_ACTION_UNREAD_CHANGED = "com.mediatek.action.UNREAD_CHANGED"; /** * M: * Extra used to indicate the unread number of which component changes. * @hide */ public static final String MTK_EXTRA_UNREAD_COMPONENT = "com.mediatek.intent.extra.UNREAD_COMPONENT"; /** * M: * The number of unread messages. * @hide */ public static final String MTK_EXTRA_UNREAD_NUMBER = "com.mediatek.intent.extra.UNREAD_NUMBER";
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 //短信
public static final void notifyNewCallsCount(SQLiteDatabase db, Context context) { Cursor c = null; if (VvmUtils.isVvmEnabled()) { c = db.rawQuery("select count(_id) from calls where type in (3,4) AND new=1", null); } else { c = db.rawQuery("select count(_id) from calls where type=3 AND new=1", null); } int newCallsCount = 0; if (c != null) { if (c.moveToFirst()) { newCallsCount = c.getInt(0); } c.close(); } LogUtils.i(TAG, "[notifyNewCallsCount] newCallsCount = " + newCallsCount); //send count=0 to clear the unread icon if (newCallsCount >= 0) { Intent newIntent = new Intent(Intent.MTK_ACTION_UNREAD_CHANGED); newIntent.putExtra(Intent.MTK_EXTRA_UNREAD_NUMBER, newCallsCount); newIntent.putExtra(Intent.MTK_EXTRA_UNREAD_COMPONENT, new ComponentName(Constants.CONTACTS_PACKAGE, Constants.CONTACTS_DIALTACTS_ACTIVITY)); context.sendBroadcast(newIntent); android.provider.Settings.System.putInt(context.getContentResolver(), Constants.CONTACTS_UNREAD_KEY, Integer .valueOf(newCallsCount)); } }3、广播的接收,需要自己在Launcher中 定义一个广播类,extends BroadcastReceiver,目录如下:
packages\apps\Launcher3\src\com\android\launcher3\MTKUnreadLoader.java重写广播方法如下:
@Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (Intent.MTK_ACTION_UNREAD_CHANGED.equals(action)) { final ComponentName componentName = (ComponentName) intent .getExtra(Intent.MTK_EXTRA_UNREAD_COMPONENT); final int unreadNum = intent.getIntExtra(Intent.MTK_EXTRA_UNREAD_NUMBER, -1); if (LauncherLog.DEBUG) { LauncherLog.d(TAG, "Receive unread broadcast: componentName = " + componentName + ", unreadNum = " + unreadNum + ", mCallbacks = " + mCallbacks + getUnreadSupportShortcutInfo()); } if (mCallbacks != null && componentName != null && unreadNum != -1) { final int index = supportUnreadFeature(componentName); if (index >= 0) { boolean ret = setUnreadNumberAt(index, unreadNum); if (ret) { final UnreadCallbacks callbacks = mCallbacks.get(); if (callbacks != null) { callbacks.bindComponentUnreadChanged(componentName, unreadNum); } } } } } }4、注册广播所在位置,这里通过代码中动态注册广播
所在目录:packages\apps\Launcher3\src\com\android\launcher3\LauncherApplication.java
注册代码如下,在onCreate方法中添加:
if (FeatureOption.MTK_LAUNCHER_UNREAD_SUPPORT) { mUnreadLoader = new MTKUnreadLoader(getApplicationContext()); // Register unread change broadcast. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.MTK_ACTION_UNREAD_CHANGED); registerReceiver(mUnreadLoader, filter); }
static void drawUnreadEventIfNeed(Canvas canvas, View icon) { ItemInfo info = (ItemInfo)icon.getTag(); if (info != null && info.unreadNum > 0) { Resources res = icon.getContext().getResources(); /// M: Meature sufficent width for unread text and background image Paint unreadTextNumberPaint = new Paint(); unreadTextNumberPaint.setTextSize(res.getDimension(R.dimen.unread_text_number_size)); unreadTextNumberPaint.setTypeface(Typeface.DEFAULT_BOLD); unreadTextNumberPaint.setColor(0xffffffff); unreadTextNumberPaint.setTextAlign(Paint.Align.CENTER); Paint unreadTextPlusPaint = new Paint(unreadTextNumberPaint); unreadTextPlusPaint.setTextSize(res.getDimension(R.dimen.unread_text_plus_size)); String unreadTextNumber; String unreadTextPlus = "+"; Rect unreadTextNumberBounds = new Rect(0, 0, 0, 0); Rect unreadTextPlusBounds = new Rect(0, 0, 0, 0); if (info.unreadNum > Launcher.MAX_UNREAD_COUNT) { unreadTextNumber = String.valueOf(Launcher.MAX_UNREAD_COUNT); unreadTextPlusPaint.getTextBounds(unreadTextPlus, 0, unreadTextPlus.length(), unreadTextPlusBounds); } else { unreadTextNumber = String.valueOf(info.unreadNum); } unreadTextNumberPaint.getTextBounds(unreadTextNumber, 0, unreadTextNumber.length(), unreadTextNumberBounds); int textHeight = unreadTextNumberBounds.height(); int textWidth = unreadTextNumberBounds.width() + unreadTextPlusBounds.width(); /// M: Draw unread background image. NinePatchDrawable unreadBgNinePatchDrawable = (NinePatchDrawable) res.getDrawable(R.drawable.ic_newevents_numberindication); int unreadBgWidth = unreadBgNinePatchDrawable.getIntrinsicWidth(); int unreadBgHeight = unreadBgNinePatchDrawable.getIntrinsicHeight(); int unreadMinWidth = (int) res.getDimension(R.dimen.unread_minWidth); if (unreadBgWidth < unreadMinWidth) { unreadBgWidth = unreadMinWidth; } int unreadTextMargin = (int) res.getDimension(R.dimen.unread_text_margin); if (unreadBgWidth < textWidth + unreadTextMargin) { unreadBgWidth = textWidth + unreadTextMargin; } if (unreadBgHeight < textHeight) { unreadBgHeight = textHeight; } Rect unreadBgBounds = new Rect(0, 0, unreadBgWidth, unreadBgHeight); unreadBgNinePatchDrawable.setBounds(unreadBgBounds); int unreadMarginTop = 0; int unreadMarginRight = 0; if (info instanceof ShortcutInfo) { if (info.container == (long) LauncherSettings.Favorites.CONTAINER_HOTSEAT) { unreadMarginTop = (int) res.getDimension(R.dimen.hotseat_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.hotseat_unread_margin_right); } else if (info.container == (long) LauncherSettings.Favorites.CONTAINER_DESKTOP) { unreadMarginTop = (int) res.getDimension(R.dimen.workspace_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.workspace_unread_margin_right); } else { unreadMarginTop = (int) res.getDimension(R.dimen.folder_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.folder_unread_margin_right); } } else if (info instanceof FolderInfo) { if (info.container == (long) LauncherSettings.Favorites.CONTAINER_HOTSEAT) { unreadMarginTop = (int) res.getDimension(R.dimen.hotseat_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.hotseat_unread_margin_right); } else if (info.container == (long) LauncherSettings.Favorites.CONTAINER_DESKTOP) { unreadMarginTop = (int) res.getDimension(R.dimen.workspace_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.workspace_unread_margin_right); } } else if (info instanceof AppInfo) { unreadMarginTop = (int) res.getDimension(R.dimen.app_list_unread_margin_top); unreadMarginRight = (int) res.getDimension(R.dimen.app_list_unread_margin_right); } int unreadBgPosX = icon.getScrollX() + icon.getWidth() - unreadBgWidth - unreadMarginRight; int unreadBgPosY = icon.getScrollY() + unreadMarginTop; canvas.save(); canvas.translate(unreadBgPosX, unreadBgPosY); unreadBgNinePatchDrawable.draw(canvas); /// M: Draw unread text. Paint.FontMetrics fontMetrics = unreadTextNumberPaint.getFontMetrics(); if (info.unreadNum > Launcher.MAX_UNREAD_COUNT) { canvas.drawText(unreadTextNumber, (unreadBgWidth - unreadTextPlusBounds.width()) / 2, (unreadBgHeight + textHeight) / 2, unreadTextNumberPaint); canvas.drawText(unreadTextPlus, (unreadBgWidth + unreadTextNumberBounds.width()) / 2, (unreadBgHeight + textHeight) / 2 + fontMetrics.ascent / 2, unreadTextPlusPaint); } else { canvas.drawText(unreadTextNumber, unreadBgWidth / 2, (unreadBgHeight + textHeight) / 2, unreadTextNumberPaint); } canvas.restore(); } }7、定义未读消息所在的xml文件,这里支持电话,短信,邮件和日历
所在目录:packages\apps\Launcher3\res\xml\unread_support_shortcuts.xml
内容如下:
<?xml version="1.0" encoding="UTF-8"?> <unreadshortcuts xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher3"> <shortcut launcher:unreadPackageName="com.android.dialer" launcher:unreadClassName="com.android.dialer.DialtactsActivity" launcher:unreadType="0" launcher:unreadKey="com_android_contacts_mtk_unread" /> <shortcut launcher:unreadPackageName="com.android.mms" launcher:unreadClassName="com.android.mms.ui.BootActivity" launcher:unreadType="0" launcher:unreadKey="com_android_mms_mtk_unread" /> <shortcut launcher:unreadPackageName="com.android.email" launcher:unreadClassName="com.android.email.activity.Welcome" launcher:unreadType="0" launcher:unreadKey="com_android_email_mtk_unread" /> <shortcut launcher:unreadPackageName="com.android.calendar" launcher:unreadClassName="com.android.calendar.AllInOneActivity" launcher:unreadType="0" launcher:unreadKey="com_android_calendar_mtk_unread" /> <shortcut launcher:unreadPackageName="com.orangelabs.rcs" launcher:unreadClassName="com.mediatek.rcse.activities.ChatMainActivity" launcher:unreadType="0" launcher:unreadKey="com_android_rcse_mtk_unread" /> <shortcut launcher:unreadPackageName="com.android.cellbroadcastreceiver" launcher:unreadClassName="com.android.cellbroadcastreceiver.CellBroadcastListActivity" launcher:unreadType="0" launcher:unreadKey="com_android_calendar_mtk_unread" /> <shortcut launcher:unreadPackageName="com.mediatek.cellbroadcastreceiver" launcher:unreadClassName="com.mediatek.cellbroadcastreceiver.CellBroadcastListActivity" launcher:unreadType="0" launcher:unreadKey="com_mediatek_cellbroadcastreceiver_mtk_unread" /> </unreadshortcuts>8、事件的图标显示,可以根据尺寸,做一张.9图片,eg: ic_newevents_numberindication.9.png
9、MTKUnreadLoader.java中定义一些接口回调方法,供Launcher3实现和调用
public interface UnreadCallbacks { /** * Bind shortcuts and application icons with the given component, and * update folders unread which contains the given component. * * @param component * @param unreadNum */ void bindComponentUnreadChanged(ComponentName component, int unreadNum); /** * Bind unread shortcut information if needed, this call back is used to * update shortcuts and folders when launcher first created. */ void bindUnreadInfoIfNeeded(); }
public void bindComponentUnreadChanged(final ComponentName component, final int unreadNum) { if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "bindComponentUnreadChanged: component = " + component + ", unreadNum = " + unreadNum + ", this = " + this); } // Post to message queue to avoid possible ANR. mHandler.post(new Runnable() { public void run() { final long start = System.currentTimeMillis(); if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindComponentUnreadChanged begin: component = " + component + ", unreadNum = " + unreadNum + ", start = " + start); } if (mWorkspace != null) { mWorkspace.updateComponentUnreadChanged(component, unreadNum); } if (mAppsCustomizeContent != null) { mAppsCustomizeContent.updateAppsUnreadChanged(component, unreadNum); } if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindComponentUnreadChanged end: current time = " + System.currentTimeMillis() + ", time used = " + (System.currentTimeMillis() - start)); } } }); } /** * M: Bind shortcuts unread number if binding process has finished. */ public void bindUnreadInfoIfNeeded() { if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "bindUnreadInfoIfNeeded: mBindingWorkspaceFinished = " + mBindingWorkspaceFinished + ", thread = " + Thread.currentThread()); } if (mBindingWorkspaceFinished) { bindWorkspaceUnreadInfo(); } if (mBindingAppsFinished) { bindAppsUnreadInfo(); } mUnreadLoadCompleted = true; } /** * M: Bind unread number to shortcuts with data in MTKUnreadLoader. */ private void bindWorkspaceUnreadInfo() { mHandler.post(new Runnable() { public void run() { final long start = System.currentTimeMillis(); if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindWorkspaceUnreadInfo begin: start = " + start); } if (mWorkspace != null) { mWorkspace.updateShortcutsAndFoldersUnread(); } if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindWorkspaceUnreadInfo end: current time = " + System.currentTimeMillis() + ",time used = " + (System.currentTimeMillis() - start)); } } }); } /** * M: Bind unread number to shortcuts with data in MTKUnreadLoader. */ private void bindAppsUnreadInfo() { mHandler.post(new Runnable() { public void run() { final long start = System.currentTimeMillis(); if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindAppsUnreadInfo begin: start = " + start); } if (mAppsCustomizeContent != null) { mAppsCustomizeContent.updateAppsUnread(); } if (LauncherLog.DEBUG_PERFORMANCE) { LauncherLog.d(TAG, "bindAppsUnreadInfo end: current time = " + System.currentTimeMillis() + ",time used = " + (System.currentTimeMillis() - start)); } } }); }
public void updateShortcutsAndFoldersUnread() { if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "updateShortcutsAndFolderUnread: this = " + this); } final ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers(); int childCount = 0; View view = null; Object tag = null; for (ShortcutAndWidgetContainer layout : childrenLayouts) { childCount = layout.getChildCount(); for (int j = 0; j < childCount; j++) { view = layout.getChildAt(j); tag = view.getTag(); if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "updateShortcutsAndFoldersUnread: tag = " + tag + ", j = " + j + ", view = " + view); } if (tag instanceof ShortcutInfo) { final ShortcutInfo info = (ShortcutInfo) tag; final Intent intent = info.intent; final ComponentName componentName = intent.getComponent(); info.unreadNum = MTKUnreadLoader.getUnreadNumberOfComponent(componentName); ((BubbleTextView) view).invalidate(); } else if (tag instanceof FolderInfo) { ((FolderIcon) view).updateFolderUnreadNum(); ((FolderIcon) view).invalidate(); } } } } /** * M: Update unread number of shortcuts and folders in workspace and hotseat * with the given component. * * @param component * @param unreadNum */ public void updateComponentUnreadChanged(ComponentName component, int unreadNum) { if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "updateComponentUnreadChanged: component = " + component + ", unreadNum = " + unreadNum); } final ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers(); int childCount = 0; View view = null; Object tag = null; for (ShortcutAndWidgetContainer layout : childrenLayouts) { childCount = layout.getChildCount(); for (int j = 0; j < childCount; j++) { view = layout.getChildAt(j); tag = view.getTag(); if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "updateComponentUnreadChanged: component = " + component + ",tag = " + tag + ",j = " + j + ",view = " + view); } if (tag instanceof ShortcutInfo) { final ShortcutInfo info = (ShortcutInfo) tag; final Intent intent = info.intent; final ComponentName componentName = intent.getComponent(); if (LauncherLog.DEBUG_UNREAD) { LauncherLog.d(TAG, "updateComponentUnreadChanged 2: find component = " + component + ",intent = " + intent + ",componentName = " + componentName); } if (componentName != null && componentName.equals(component)) { LauncherLog.d(TAG, "updateComponentUnreadChanged 1: find component = " + component + ",tag = " + tag + ",j = " + j + ",cellX = " + info.cellX + ",cellY = " + info.cellY); info.unreadNum = unreadNum; ((BubbleTextView) view).invalidate(); } } else if (tag instanceof FolderInfo) { ((FolderIcon) view).updateFolderUnreadNum(component, unreadNum); ((FolderIcon) view).invalidate(); } } } /// M: Update shortcut within folder if open folder exists. Folder openFolder = getOpenFolder(); if (openFolder != null) { openFolder.updateContentUnreadNum(); }
具体:在各自的onDraw方法中添加MTKUnreadLoader.drawUnreadEventIfNeed(canvas,this).
eg: FolderIcon.java在dispatchDraw()方法中添加
BubbleTextView.java在draw()方法中添加