diff --git a/README.md b/README.md index 3122655..b88b8ab 100644 --- a/README.md +++ b/README.md @@ -7,54 +7,69 @@ The ShortcutBadger makes your Android App showing the count of unread messages a - - - + + + - - - + + + + + + + + - - +
-

Android

-
(before 4.4)
-
(Deprecated since 1.1.0)
-
- -
-

Sony

-
- -
-

Samsung

-
- -
+

Sony

+
+ +
+

Samsung

+
+ +
+

LG

+
+ +
-

LG

-
- -
-

HTC

-
- -
-

Xiaomi

-
- -
+

HTC

+
+ +
+

Xiaomi

+
+ +
+

ASUS

+
+ +
+

ADW

+
+ +
+

APEX

+
+ +
+

NOVA

+
+ +
-

ASUS

+

Android

+
(before 4.4)
+
(Deprecated since 1.1.0)

- -
- +
+ Nova launcher with TeslaUnread,Apex launcher,Adw Launcher provided by [notz](https://github.com/notz)
Solid launcher provided by [MajeurAndroid](https://github.com/MajeurAndroid) @@ -70,18 +85,17 @@ USAGE
2. Add dependencies for ShortcutBadger, it's available from maven now. dependencies { - compile 'me.leolin:ShortcutBadger:1.1.0@aar' + compile 'me.leolin:ShortcutBadger:1.1.1@aar' }
3. Add the codes below: int badgeCount = 1; - try { - ShortcutBadger.setBadge(getApplicationContext(), badgeCount); - } catch (ShortcutBadgeException e) { - //handle the Exception - } -
4. If you want to remove the badge, just set the badgeCount as 0. + ShortcutBadger.with(getApplicationContext()).count(badgeCount); + +
4. If you want to remove the badge + + ShortcutBadger.with(getApplicationContext()).remove();


@@ -105,6 +119,11 @@ Please use version 1.1.0+ CHANGE LOG =================================== +1.1.1:
+Add DefaultBadger because some launchers use android.intent.action.BADGE_COUNT_UPDATE to update count. +
+Since the ShortcutBadgerException is helpless. So change api to set badge and never have to handle the exception again. +

1.1.0:
Remove Android Launcher support due to Google Play Developer Term Violation since 4.4

diff --git a/SampleApp/src/main/java/me/leolin/shortcutbadger/example/MainActivity.java b/SampleApp/src/main/java/me/leolin/shortcutbadger/example/MainActivity.java index f58a07c..93cdcd3 100644 --- a/SampleApp/src/main/java/me/leolin/shortcutbadger/example/MainActivity.java +++ b/SampleApp/src/main/java/me/leolin/shortcutbadger/example/MainActivity.java @@ -10,7 +10,6 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import me.leolin.shortcutbadger.ShortcutBadgeException; import me.leolin.shortcutbadger.ShortcutBadger; @@ -29,20 +28,17 @@ protected void onCreate(Bundle savedInstanceState) { button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + int badgeCount = 0; try { - int badgeCount = 0; - try { - badgeCount = Integer.parseInt(numInput.getText().toString()); - } catch (NumberFormatException e) { - Toast.makeText(getApplicationContext(), "Error input", Toast.LENGTH_SHORT).show(); - } - - ShortcutBadger.setBadge(getApplicationContext(), badgeCount); - - Toast.makeText(getApplicationContext(), "Set count=" + badgeCount, Toast.LENGTH_SHORT).show(); - } catch (ShortcutBadgeException e) { - Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); + badgeCount = Integer.parseInt(numInput.getText().toString()); + } catch (NumberFormatException e) { + Toast.makeText(getApplicationContext(), "Error input", Toast.LENGTH_SHORT).show(); } + +// ShortcutBadger.setBadge(getApplicationContext(), badgeCount); + ShortcutBadger.with(getApplicationContext()).count(badgeCount); + + Toast.makeText(getApplicationContext(), "Set count=" + badgeCount, Toast.LENGTH_SHORT).show(); } }); diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadgeException.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadgeException.java index f6fdc55..5aad647 100644 --- a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadgeException.java +++ b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadgeException.java @@ -1,12 +1,6 @@ package me.leolin.shortcutbadger; -/** - * Created with IntelliJ IDEA. - * User: leolin - * Date: 2013/11/14 - * Time: 下午6:19 - * To change this template use File | Settings | File Templates. - */ +@Deprecated public class ShortcutBadgeException extends Exception { public ShortcutBadgeException(String message) { super(message); diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadger.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadger.java index c03d4be..7abfd68 100644 --- a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadger.java +++ b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/ShortcutBadger.java @@ -6,10 +6,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; +import android.util.Log; import me.leolin.shortcutbadger.impl.*; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.List; @@ -19,12 +19,12 @@ */ public abstract class ShortcutBadger { + private static final String LOG_TAG = ShortcutBadger.class.getSimpleName(); + private static final List> BADGERS = new LinkedList>(); static { BADGERS.add(AdwHomeBadger.class); -// BADGERS.add(AndroidHomeBadger.class); -// BADGERS.add(Android2HomeBadger.class); BADGERS.add(ApexHomeBadger.class); BADGERS.add(LGHomeBadger.class); BADGERS.add(NewHtcHomeBadger.class); @@ -36,86 +36,73 @@ public abstract class ShortcutBadger { BADGERS.add(AsusHomeLauncher.class); } - private static final String MESSAGE_NOT_SUPPORT_BADGE_COUNT = "ShortBadger is currently not support the badgeCount \"%d\""; - private static final String MESSAGE_NOT_SUPPORT_THIS_HOME = "ShortcutBadger is currently not support the home launcher package \"%s\""; - - private static final int MIN_BADGE_COUNT = 0; - private static final int MAX_BADGE_COUNT = 99; - private static ShortcutBadger mShortcutBadger; - private ShortcutBadger() { - } - - protected Context mContext; - - protected ShortcutBadger(Context context) { - this.mContext = context; + public static ShortcutBadger with(Context context) { + return getShortcutBadger(context); } - protected abstract void executeBadge(int badgeCount) throws ShortcutBadgeException; public static void setBadge(Context context, int badgeCount) throws ShortcutBadgeException { - //badgeCount should between 0 to 99 - if (badgeCount < MIN_BADGE_COUNT || badgeCount > MAX_BADGE_COUNT) { - String exceptionMessage = String.format(MESSAGE_NOT_SUPPORT_BADGE_COUNT, badgeCount); - throw new ShortcutBadgeException(exceptionMessage); - } - - //find the home launcher Package - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_HOME); - ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); - String currentHomePackage = resolveInfo.activityInfo.packageName; - - try { - ShortcutBadger shortcutBadger = getShortcutBadger(currentHomePackage, context); - - //not support this home launcher package - if (shortcutBadger == null) { - String exceptionMessage = String.format(MESSAGE_NOT_SUPPORT_THIS_HOME, currentHomePackage); - throw new ShortcutBadgeException(exceptionMessage); - } - - shortcutBadger.executeBadge(badgeCount); + getShortcutBadger(context).executeBadge(badgeCount); } catch (Throwable e) { throw new ShortcutBadgeException("Unable to execute badge:" + e.getMessage()); } } - private static ShortcutBadger getShortcutBadger(String currentHomePackage, Context context) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { + private static ShortcutBadger getShortcutBadger(Context context) { if (mShortcutBadger != null) { return mShortcutBadger; } + Log.d(LOG_TAG, "Finding badger"); - // Workaround for Meizu: - // Meizu declare 'com.android.launcher', but hold something else - // Icons get duplicated on restart after badge change - if (Build.MANUFACTURER.toLowerCase().contains("meizu")) { - return null; - } - - if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) { - mShortcutBadger = new XiaomiHomeBadger(context); - return mShortcutBadger; - } + //find the home launcher Package + try { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + String currentHomePackage = resolveInfo.activityInfo.packageName; + + if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) { + mShortcutBadger = new XiaomiHomeBadger(context); + return mShortcutBadger; + } - for (Class badger : BADGERS) { - Constructor constructor = badger.getConstructor(Context.class); - ShortcutBadger shortcutBadger = constructor.newInstance(context); - if (shortcutBadger.getSupportLaunchers().contains(currentHomePackage)) { - mShortcutBadger = shortcutBadger; - break; + for (Class badger : BADGERS) { + Constructor constructor = badger.getConstructor(Context.class); + ShortcutBadger shortcutBadger = constructor.newInstance(context); + if (shortcutBadger.getSupportLaunchers().contains(currentHomePackage)) { + mShortcutBadger = shortcutBadger; + break; + } } + } catch (Exception e) { + Log.e(LOG_TAG, e.getMessage(), e); } + if (mShortcutBadger == null) { + mShortcutBadger = new DefaultBadger(context); + } + Log.d(LOG_TAG, "Returning badger:" + mShortcutBadger.getClass().getCanonicalName()); return mShortcutBadger; } - public abstract List getSupportLaunchers(); + + private ShortcutBadger() { + } + + protected Context mContext; + + protected ShortcutBadger(Context context) { + this.mContext = context; + } + + protected abstract void executeBadge(int badgeCount) throws ShortcutBadgeException; + + protected abstract List getSupportLaunchers(); protected String getEntryActivityName() { ComponentName componentName = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()).getComponent(); @@ -125,4 +112,16 @@ protected String getEntryActivityName() { protected String getContextPackageName() { return mContext.getPackageName(); } + + public void count(int count) { + try { + executeBadge(count); + } catch (Exception e) { + Log.e(LOG_TAG, e.getMessage(), e); + } + } + + public void remove() { + count(0); + } } diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/Android2HomeBadger.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/Android2HomeBadger.java deleted file mode 100644 index e27b848..0000000 --- a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/Android2HomeBadger.java +++ /dev/null @@ -1,47 +0,0 @@ -package me.leolin.shortcutbadger.impl; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.net.Uri; -import me.leolin.shortcutbadger.ShortcutBadgeException; -import me.leolin.shortcutbadger.ShortcutBadger; -import me.leolin.shortcutbadger.util.ImageUtil; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Leo Lin - */ -@Deprecated -public class Android2HomeBadger extends ShortcutBadger { - private static final String CONTENT_URI = "content://com.android.launcher2.settings/favorites?notify=true"; - - public Android2HomeBadger(Context context) { - super(context); - } - - @Override - protected void executeBadge(int badgeCount) throws ShortcutBadgeException { - byte[] bytes = ImageUtil.drawBadgeOnAppIcon(mContext, badgeCount); - String appName = mContext.getResources().getText(mContext.getResources().getIdentifier("app_name", - "string", getContextPackageName())).toString(); - - Uri mUri = Uri.parse(CONTENT_URI); - ContentResolver contentResolver = mContext.getContentResolver(); - ContentValues contentValues = new ContentValues(); - contentValues.put("iconType", 1); - contentValues.put("itemType", 1); - contentValues.put("icon", bytes); - contentResolver.update(mUri, contentValues, "title=?", new String[]{appName}); - } - - @Override - public List getSupportLaunchers() { - return Arrays.asList( - "com.android.launcher2", - "com.google.android.googlequicksearchbox" - ); - } -} diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/AndroidHomeBadger.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/AndroidHomeBadger.java deleted file mode 100644 index 8f4e83f..0000000 --- a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/AndroidHomeBadger.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.leolin.shortcutbadger.impl; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.net.Uri; -import me.leolin.shortcutbadger.ShortcutBadgeException; -import me.leolin.shortcutbadger.ShortcutBadger; -import me.leolin.shortcutbadger.util.ImageUtil; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Leo Lin - */ -@Deprecated -public class AndroidHomeBadger extends ShortcutBadger { - private static final String CONTENT_URI = "content://com.android.launcher2.settings/favorites?notify=true"; - - public AndroidHomeBadger(Context context) { - super(context); - } - - @Override - protected void executeBadge(int badgeCount) throws ShortcutBadgeException { - byte[] bytes = ImageUtil.drawBadgeOnAppIcon(mContext, badgeCount); - String appName = mContext.getResources().getText(mContext.getResources().getIdentifier("app_name", - "string", getContextPackageName())).toString(); - - Uri mUri = Uri.parse(CONTENT_URI); - ContentResolver contentResolver = mContext.getContentResolver(); - ContentValues contentValues = new ContentValues(); - contentValues.put("iconType", 1); - contentValues.put("itemType", 1); - contentValues.put("icon", bytes); - contentResolver.update(mUri, contentValues, "title=?", new String[]{appName}); - } - - @Override - public List getSupportLaunchers() { - return Arrays.asList( - "com.android.launcher" - ); - } -} diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/DefaultBadger.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/DefaultBadger.java new file mode 100644 index 0000000..2963b5b --- /dev/null +++ b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/impl/DefaultBadger.java @@ -0,0 +1,36 @@ +package me.leolin.shortcutbadger.impl; + +import android.content.Context; +import android.content.Intent; +import me.leolin.shortcutbadger.ShortcutBadger; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author leolin + */ +public class DefaultBadger extends ShortcutBadger { + private static final String INTENT_ACTION = "android.intent.action.BADGE_COUNT_UPDATE"; + private static final String INTENT_EXTRA_BADGE_COUNT = "badge_count"; + private static final String INTENT_EXTRA_PACKAGENAME = "badge_count_package_name"; + private static final String INTENT_EXTRA_ACTIVITY_NAME = "badge_count_class_name"; + + public DefaultBadger(Context context) { + super(context); + } + + @Override + protected void executeBadge(int badgeCount) { + Intent intent = new Intent(INTENT_ACTION); + intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount); + intent.putExtra(INTENT_EXTRA_PACKAGENAME, getContextPackageName()); + intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, getEntryActivityName()); + mContext.sendBroadcast(intent); + } + + @Override + public List getSupportLaunchers() { + return new ArrayList(0); + } +} diff --git a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/util/ImageUtil.java b/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/util/ImageUtil.java deleted file mode 100644 index 8c67d04..0000000 --- a/ShortcutBadger/src/main/java/me/leolin/shortcutbadger/util/ImageUtil.java +++ /dev/null @@ -1,109 +0,0 @@ -package me.leolin.shortcutbadger.util; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.graphics.*; -import android.graphics.drawable.Drawable; -import me.leolin.shortcutbadger.ShortcutBadgeException; - -import java.io.ByteArrayOutputStream; - -/** - * Created with IntelliJ IDEA. - * User: leolin - * Date: 2013/11/14 - * Time: 下午7:15 - * To change this template use File | Settings | File Templates. - */ -public class ImageUtil { - public static Bitmap drawableToBitmap(Drawable drawable) { - - Bitmap bitmap = Bitmap - .createBitmap( - drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), - drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 - : Bitmap.Config.RGB_565); - Canvas canvas = new Canvas(bitmap); - - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - drawable.draw(canvas); - return bitmap; - } - - public static byte[] bitmapToByteArray(Bitmap bitmap) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); - return baos.toByteArray(); - - } - - public static byte[] drawBadgeOnAppIcon(Context context, int badgeCount) throws ShortcutBadgeException { - - Bitmap appIcon; - String gText = String.valueOf(badgeCount); - - try { - Drawable iconDrawable = context.getPackageManager().getApplicationIcon(context.getPackageName()); - appIcon = drawableToBitmap(iconDrawable); - } catch (PackageManager.NameNotFoundException e) { - throw new ShortcutBadgeException("Could not load the app Icon"); - } - - if (appIcon == null) { - throw new ShortcutBadgeException("Could not load the app Icon"); - } - - if (badgeCount == 0) { - return bitmapToByteArray(appIcon); - } - - float scale = context.getResources().getDisplayMetrics().density; - - android.graphics.Bitmap.Config bitmapConfig = - appIcon.getConfig(); - // set default bitmap config if none - if (bitmapConfig == null) { - bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888; - } - // resource bitmaps are imutable, - // so we need to convert it to mutable one - appIcon = appIcon.copy(bitmapConfig, true); - - float width = appIcon.getWidth(); - float height = appIcon.getHeight(); - float radius = ((width > height ? width : height) / 4); - float cx = appIcon.getWidth() - radius; - float cy = radius; - - Canvas canvas = new Canvas(appIcon); - //ANTI_ALIAS to avoid glitched circles - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setColor(Color.WHITE); - canvas.drawCircle(cx, cy, radius, paint); - paint.setColor(Color.RED); - canvas.drawCircle(cx, cy, radius * 6 / 7, paint); - - paint.setColor(Color.WHITE); - // text size in pixels - int textSize = (int) (radius * 0.7); - if (gText.length() > 1) { - textSize = (int) (radius * 0.5); - } - paint.setTextSize((int) (textSize * scale)); - paint.setFakeBoldText(true); - // draw text to the Canvas center - Rect bounds = new Rect(); - paint.getTextBounds(gText, 0, gText.length(), bounds); - float bw = bounds.width() / 2; - if (gText.endsWith("1")) { - bw *= 1.25; - } - float bh = bounds.height() / 2; - canvas.drawText(gText, cx - bw, cy + bh, paint); - - return bitmapToByteArray(appIcon); - } - - -} diff --git a/screenshots/ss_adw.png b/screenshots/ss_adw.png new file mode 100644 index 0000000..35ba93f Binary files /dev/null and b/screenshots/ss_adw.png differ diff --git a/screenshots/ss_apex.png b/screenshots/ss_apex.png new file mode 100644 index 0000000..a660e8b Binary files /dev/null and b/screenshots/ss_apex.png differ diff --git a/screenshots/ss_nova.png b/screenshots/ss_nova.png new file mode 100644 index 0000000..ce26b1d Binary files /dev/null and b/screenshots/ss_nova.png differ