From 9b398417ff00bb67a43579c748fd335effad1c5b Mon Sep 17 00:00:00 2001 From: huiwan Date: Mon, 10 Nov 2014 10:35:03 -0800 Subject: Launcher: show unread notify info number at APP icon on Launcher Show APP's unread info number at Launcher: - Register a receiver to receive the UNREAD_CHANGED event to update the APP icon - When the unread number changed, recreate the icon bitmap of icon cache Change-Id: I7dd0fb2c29959f1584682965fb1476e3f3c77739 --- src/com/android/launcher3/AllAppsList.java | 37 ++++++++++-- src/com/android/launcher3/AppInfo.java | 4 ++ src/com/android/launcher3/IconCache.java | 16 +++--- src/com/android/launcher3/LauncherAppState.java | 7 +++ src/com/android/launcher3/LauncherApplication.java | 6 +- src/com/android/launcher3/LauncherModel.java | 65 ++++++++++++++++++++++ src/com/android/launcher3/Utilities.java | 45 +++++++++++++++ 7 files changed, 167 insertions(+), 13 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java index 38d2fa541..f9900e604 100644 --- a/src/com/android/launcher3/AllAppsList.java +++ b/src/com/android/launcher3/AllAppsList.java @@ -18,11 +18,6 @@ package com.android.launcher3; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; - import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserHandleCompat; @@ -231,4 +226,36 @@ class AllAppsList { } return null; } + + public AppInfo unreadNumbersChanged(Context context, ComponentName component, + int unreadNum) { + + if (component == null) { return null; } + + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); + List matches = + launcherApps.getActivityList(component.getPackageName(), myUserHandle); + + for (LauncherActivityInfoCompat launcherActivityInfoCompat : matches) { + if (component.getPackageName().equals( + launcherActivityInfoCompat.getComponentName().getPackageName())) { + + AppInfo appInfo = findApplicationInfoLocked( + component.getPackageName(), myUserHandle, + component.getClassName()); + + if (appInfo == null) { + return null; + } else { + appInfo.unreadNum = unreadNum; + mIconCache.remove(appInfo.componentName, myUserHandle); + mIconCache.getTitleAndIcon(appInfo, launcherActivityInfoCompat, null); + return appInfo; + } + } + } + + return null; + } } diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java index bfcad84b3..b1af370b1 100644 --- a/src/com/android/launcher3/AppInfo.java +++ b/src/com/android/launcher3/AppInfo.java @@ -56,6 +56,10 @@ public class AppInfo extends ItemInfo { ComponentName componentName; + int count; + + int unreadNum = 0; + static final int DOWNLOADED_FLAG = 1; static final int UPDATED_SYSTEM_APP_FLAG = 2; diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index bb71d776c..03684f600 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -245,7 +245,7 @@ public class IconCache { HashMap labelCache) { synchronized (mCache) { CacheEntry entry = cacheLocked(application.componentName, info, labelCache, - info.getUser(), false); + info.getUser(), false, application.unreadNum); application.title = entry.title; application.iconBitmap = entry.icon; @@ -267,7 +267,7 @@ public class IconCache { } LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); - CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon, -1); if (title != null) { entry.title = title; entry.contentDescription = mUserManager.getBadgedLabelForUser(title, user); @@ -292,7 +292,8 @@ public class IconCache { } else { LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); - CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon, + -1); shortcutInfo.setIcon(entry.icon); shortcutInfo.title = entry.title; @@ -316,7 +317,7 @@ public class IconCache { return null; } - CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false); + CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false, -1); return entry.icon; } } @@ -326,10 +327,11 @@ public class IconCache { } private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info, - HashMap labelCache, UserHandleCompat user, boolean usePackageIcon) { + HashMap labelCache, UserHandleCompat user, + boolean usePackageIcon, int unreadNum) { CacheKey cacheKey = new CacheKey(componentName, user); CacheEntry entry = mCache.get(cacheKey); - if (entry == null) { + if (entry == null || unreadNum >= 0) { entry = new CacheEntry(); mCache.put(cacheKey, entry); @@ -347,7 +349,7 @@ public class IconCache { entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user); entry.icon = Utilities.createIconBitmap( - info.getBadgedIcon(mIconDpi), mContext); + info.getBadgedIcon(mIconDpi), mContext, unreadNum); } else { entry.title = ""; Bitmap preloaded = getPreloadedIcon(componentName, user); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 128065ab6..a207f1e2c 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -111,6 +111,13 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { filter = new IntentFilter(); filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); sContext.registerReceiver(mModel, filter); + + filter = new IntentFilter(); + if (LauncherApplication.LAUNCHER_SHOW_UNREAD_NUMBER) { + filter.addAction(LauncherModel.ACTION_UNREAD_CHANGED); + sContext.registerReceiver(mModel, filter); + } + filter = new IntentFilter(); filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED); sContext.registerReceiver(mModel, filter); diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java index 8b179f1e7..f0a08ffbe 100644 --- a/src/com/android/launcher3/LauncherApplication.java +++ b/src/com/android/launcher3/LauncherApplication.java @@ -19,9 +19,13 @@ package com.android.launcher3; import android.app.Application; public class LauncherApplication extends Application { + public static boolean LAUNCHER_SHOW_UNREAD_NUMBER; + @Override public void onCreate() { super.onCreate(); + LAUNCHER_SHOW_UNREAD_NUMBER = getResources().getBoolean( + R.bool.config_launcher_show_unread_number); LauncherAppState.setApplicationContext(this); LauncherAppState.getInstance(); } @@ -31,4 +35,4 @@ public class LauncherApplication extends Application { super.onTerminate(); LauncherAppState.getInstance().onTerminate(); } -} \ No newline at end of file +} diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 79e7cbf43..abd41b0bc 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -178,6 +178,9 @@ public class LauncherModel extends BroadcastReceiver // + public static final String ACTION_UNREAD_CHANGED = + "com.android.launcher.action.UNREAD_CHANGED"; + private IconCache mIconCache; protected int mPreviousConfigMcc; @@ -214,6 +217,58 @@ public class LauncherModel extends BroadcastReceiver public void dumpLogsToLocalData(); } + private HashMap unreadChangedMap = + new HashMap(); + + private class UnreadInfo { + ComponentName mComponentName; + int mUnreadNum; + + public UnreadInfo(ComponentName componentName, int unreadNum) { + mComponentName = componentName; + mUnreadNum = unreadNum; + } + } + + private class UnreadNumberChangeTask implements Runnable { + public void run() { + ArrayList unreadInfos = new ArrayList(); + synchronized (unreadChangedMap) { + unreadInfos.addAll(unreadChangedMap.values()); + unreadChangedMap.clear(); + } + + Context context = mApp.getContext(); + final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == null) { + Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading."); + return; + } + + final ArrayList unreadChangeFinal = new ArrayList(); + for (UnreadInfo uInfo : unreadInfos) { + AppInfo info = mBgAllAppsList.unreadNumbersChanged(context, + uInfo.mComponentName, uInfo.mUnreadNum); + if (info != null) { + unreadChangeFinal.add(info); + } + } + + if (unreadChangeFinal.isEmpty()) return; + + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + callbacks.bindAppsUpdated(unreadChangeFinal); + } + } + }); + } + } + + private UnreadNumberChangeTask mUnreadUpdateTask = new UnreadNumberChangeTask(); + public interface ItemInfoFilter { public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn); } @@ -1334,6 +1389,16 @@ public class LauncherModel extends BroadcastReceiver callbacks.bindSearchablesChanged(); } } + } else if (ACTION_UNREAD_CHANGED.equals(action)) { + ComponentName componentName = intent.getParcelableExtra("component_name"); + int unreadNum = intent.getIntExtra("unread_number", 0); + + if (componentName == null) return; + synchronized (unreadChangedMap) { + unreadChangedMap.put(componentName, new UnreadInfo(componentName, unreadNum)); + } + sWorker.removeCallbacks(mUnreadUpdateTask); + sWorker.post(mUnreadUpdateTask); } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 80d4b22ce..addd74cfc 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -32,8 +32,11 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Paint.Style; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; @@ -75,6 +78,48 @@ public final class Utilities { static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate"; public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY); + static Bitmap createIconBitmap(Drawable icon, Context context, int count) { + Bitmap b = createIconBitmap(icon, context); + + if (!LauncherApplication.LAUNCHER_SHOW_UNREAD_NUMBER || count <= 0) { + return b; + } + + int textureWidth = b.getWidth(); + final Resources resources = context.getResources(); + final Canvas canvas = sCanvas; + canvas.setBitmap(b); + + float textsize = resources.getDimension(R.dimen.infomation_count_textsize); + Paint countPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DEV_KERN_TEXT_FLAG); + countPaint.setColor(Color.WHITE); + countPaint.setTextSize(textsize); + + String text = String.valueOf(count); + if (count >= 1000) { + text = "999+"; + } + + float count_hight = resources.getDimension(R.dimen.infomation_count_height); + float padding = resources.getDimension(R.dimen.infomation_count_padding); + float radius = resources.getDimension(R.dimen.infomation_count_circle_radius); + int textwidth = (int) (countPaint.measureText(text) + 1); + float width =textwidth + padding * 2; + width = Math.max(width, resources.getDimensionPixelSize(R.dimen.infomation_count_min_width)); + + RectF rect = new RectF(textureWidth - width -1, 1, textureWidth - 1, count_hight + 1); + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setColor(resources.getColor(R.color.infomation_count_circle_color)); + canvas.drawRoundRect(rect , radius, radius, paint); + + float x = textureWidth - (width + textwidth ) / 2 - 1; + float y = textsize; + canvas.drawText(text, x, y, countPaint); + + return b; + } + /** * Returns a FastBitmapDrawable with the icon, accurately sized. */ -- cgit v1.2.3