Update to 1.1.1.

Add more launcher screenshot.
Add DefaultBadger.
This commit is contained in:
Leo Lin 2015-05-15 01:04:57 +08:00
parent c3f9106ee9
commit e420d43557
11 changed files with 179 additions and 337 deletions

109
README.md
View File

@ -6,6 +6,57 @@ The ShortcutBadger makes your Android App showing the count of unread messages a
# Support launchers:<br/>
<table>
<tr>
<td width="130">
<h3>Sony</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_sony.png"/>
</td>
<td width="130">
<h3>Samsung</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_samsung.png"/>
</td>
<td width="130">
<h3>LG</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_lg.png"/>
</td>
</tr>
<tr>
<td width="130">
<h3>HTC</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_htc.png"/>
</td>
<td width="130">
<h3>Xiaomi</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_xiaomi.png"/>
</td>
<td width="130">
<h3>ASUS</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_asus.png"/>
</td>
<tr>
<td width="130">
<h3>ADW</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_adw.png"/>
</td>
<td width="130">
<h3>APEX</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_apex.png"/>
</td>
<td width="130">
<h3>NOVA</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_nova.png"/>
</td>
</tr>
<tr>
<td width="130">
<h3>Android</h3>
@ -14,47 +65,11 @@ The ShortcutBadger makes your Android App showing the count of unread messages a
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_android.png"/>
</td>
<td width="130">
<h3>Sony</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_sony.png"/>
</td>
<td width="130">
<h3>Samsung</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_samsung.png"/>
</td>
</tr>
<tr>
<td width="130">
<h3>LG</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_lg.png"/>
</td>
<td width="130">
<h3>HTC</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_htc.png"/>
</td>
<td width="130">
<h3>Xiaomi</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_xiaomi.png"/>
</td>
</tr>
<tr>
<td width="130">
<h3>ASUS</h3>
<br>
<img src="https://raw.github.com/leolin310148/ShortcutBadger/master/screenshots/ss_asus.png"/>
</td>
<td width="130">
</td>
<td width="130">
</td>
</tr>
</table>
Nova launcher with TeslaUnread,Apex launcher,Adw Launcher provided by [notz](https://github.com/notz)</br/>
Solid launcher provided by [MajeurAndroid](https://github.com/MajeurAndroid)
@ -70,18 +85,17 @@ USAGE
<br/>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'
}
<br/>3. Add the codes below:
int badgeCount = 1;
try {
ShortcutBadger.setBadge(getApplicationContext(), badgeCount);
} catch (ShortcutBadgeException e) {
//handle the Exception
}
<br/>4. If you want to remove the badge, just set the badgeCount as 0.
ShortcutBadger.with(getApplicationContext()).count(badgeCount);
<br/>4. If you want to remove the badge
ShortcutBadger.with(getApplicationContext()).remove();
<br/>
<br/>
<br/>
@ -105,6 +119,11 @@ Please use version 1.1.0+
CHANGE LOG
===================================
1.1.1:<br/>
Add DefaultBadger because some launchers use android.intent.action.BADGE_COUNT_UPDATE to update count.
<br/>
Since the ShortcutBadgerException is helpless. So change api to set badge and never have to handle the exception again.
<br/><br/>
1.1.0:<br/>
Remove Android Launcher support due to Google Play Developer Term Violation since 4.4
<br/><br/>

View File

@ -10,7 +10,6 @@ import android.widget.Button;
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 @@ public class MainActivity extends Activity {
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();
}
});

View File

@ -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);

View File

@ -6,10 +6,10 @@ import android.content.Intent;
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 @@ import java.util.List;
*/
public abstract class ShortcutBadger {
private static final String LOG_TAG = ShortcutBadger.class.getSimpleName();
private static final List<Class<? extends ShortcutBadger>> BADGERS = new LinkedList<Class<? extends ShortcutBadger>>();
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,14 +36,61 @@ 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;
public static ShortcutBadger with(Context context) {
return getShortcutBadger(context);
}
public static void setBadge(Context context, int badgeCount) throws ShortcutBadgeException {
try {
getShortcutBadger(context).executeBadge(badgeCount);
} catch (Throwable e) {
throw new ShortcutBadgeException("Unable to execute badge:" + e.getMessage());
}
}
private static ShortcutBadger getShortcutBadger(Context context) {
if (mShortcutBadger != null) {
return mShortcutBadger;
}
Log.d(LOG_TAG, "Finding badger");
//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<? extends ShortcutBadger> badger : BADGERS) {
Constructor<? extends ShortcutBadger> 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;
}
private ShortcutBadger() {
}
@ -55,67 +102,7 @@ public abstract class ShortcutBadger {
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);
} 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 {
if (mShortcutBadger != null) {
return mShortcutBadger;
}
// 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;
}
for (Class<? extends ShortcutBadger> badger : BADGERS) {
Constructor<? extends ShortcutBadger> constructor = badger.getConstructor(Context.class);
ShortcutBadger shortcutBadger = constructor.newInstance(context);
if (shortcutBadger.getSupportLaunchers().contains(currentHomePackage)) {
mShortcutBadger = shortcutBadger;
break;
}
}
return mShortcutBadger;
}
public abstract List<String> getSupportLaunchers();
protected abstract List<String> getSupportLaunchers();
protected String getEntryActivityName() {
ComponentName componentName = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()).getComponent();
@ -125,4 +112,16 @@ public abstract class ShortcutBadger {
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);
}
}

View File

@ -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<String> getSupportLaunchers() {
return Arrays.asList(
"com.android.launcher2",
"com.google.android.googlequicksearchbox"
);
}
}

View File

@ -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<String> getSupportLaunchers() {
return Arrays.asList(
"com.android.launcher"
);
}
}

View File

@ -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<String> getSupportLaunchers() {
return new ArrayList<String>(0);
}
}

View File

@ -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);
}
}

BIN
screenshots/ss_adw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
screenshots/ss_apex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
screenshots/ss_nova.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB