mirror of https://github.com/M66B/FairEmail.git
parent
088e151550
commit
819e86615f
@ -0,0 +1,25 @@
|
||||
package me.leolin.shortcutbadger;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Badger {
|
||||
|
||||
/**
|
||||
* Called when user attempts to update notification count
|
||||
* @param context Caller context
|
||||
* @param componentName Component containing package and class name of calling application's
|
||||
* launcher activity
|
||||
* @param badgeCount Desired notification count
|
||||
* @throws ShortcutBadgeException
|
||||
*/
|
||||
void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* Called to let {@link ShortcutBadger} knows which launchers are supported by this badger. It should return a
|
||||
* @return List containing supported launchers package names
|
||||
*/
|
||||
List<String> getSupportLaunchers();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package me.leolin.shortcutbadger;
|
||||
|
||||
public class ShortcutBadgeException extends Exception {
|
||||
public ShortcutBadgeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ShortcutBadgeException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,280 @@
|
||||
package me.leolin.shortcutbadger;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.impl.AdwHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.ApexHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.AsusHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.DefaultBadger;
|
||||
import me.leolin.shortcutbadger.impl.EverythingMeHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.HuaweiHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.NewHtcHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.NovaHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.OPPOHomeBader;
|
||||
import me.leolin.shortcutbadger.impl.SamsungHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.SonyHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.VivoHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.YandexLauncherBadger;
|
||||
import me.leolin.shortcutbadger.impl.ZTEHomeBadger;
|
||||
import me.leolin.shortcutbadger.impl.ZukHomeBadger;
|
||||
|
||||
|
||||
/**
|
||||
* @author Leo Lin
|
||||
*/
|
||||
public final class ShortcutBadger {
|
||||
|
||||
private static final String LOG_TAG = "ShortcutBadger";
|
||||
private static final int SUPPORTED_CHECK_ATTEMPTS = 3;
|
||||
|
||||
private static final List<Class<? extends Badger>> BADGERS = new LinkedList<Class<? extends Badger>>();
|
||||
|
||||
private volatile static Boolean sIsBadgeCounterSupported;
|
||||
private final static Object sCounterSupportedLock = new Object();
|
||||
|
||||
static {
|
||||
BADGERS.add(AdwHomeBadger.class);
|
||||
BADGERS.add(ApexHomeBadger.class);
|
||||
BADGERS.add(DefaultBadger.class);
|
||||
BADGERS.add(NewHtcHomeBadger.class);
|
||||
BADGERS.add(NovaHomeBadger.class);
|
||||
BADGERS.add(SonyHomeBadger.class);
|
||||
BADGERS.add(AsusHomeBadger.class);
|
||||
BADGERS.add(HuaweiHomeBadger.class);
|
||||
BADGERS.add(OPPOHomeBader.class);
|
||||
BADGERS.add(SamsungHomeBadger.class);
|
||||
BADGERS.add(ZukHomeBadger.class);
|
||||
BADGERS.add(VivoHomeBadger.class);
|
||||
BADGERS.add(ZTEHomeBadger.class);
|
||||
BADGERS.add(EverythingMeHomeBadger.class);
|
||||
BADGERS.add(YandexLauncherBadger.class);
|
||||
}
|
||||
|
||||
private static Badger sShortcutBadger;
|
||||
private static ComponentName sComponentName;
|
||||
|
||||
/**
|
||||
* Tries to update the notification count
|
||||
*
|
||||
* @param context Caller context
|
||||
* @param badgeCount Desired badge count
|
||||
* @return true in case of success, false otherwise
|
||||
*/
|
||||
public static boolean applyCount(Context context, int badgeCount) {
|
||||
try {
|
||||
applyCountOrThrow(context, badgeCount);
|
||||
return true;
|
||||
} catch (ShortcutBadgeException e) {
|
||||
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
|
||||
Log.d(LOG_TAG, "Unable to execute badge", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to update the notification count, throw a {@link ShortcutBadgeException} if it fails
|
||||
*
|
||||
* @param context Caller context
|
||||
* @param badgeCount Desired badge count
|
||||
*/
|
||||
public static void applyCountOrThrow(Context context, int badgeCount) throws ShortcutBadgeException {
|
||||
if (sShortcutBadger == null) {
|
||||
boolean launcherReady = initBadger(context);
|
||||
|
||||
if (!launcherReady)
|
||||
throw new ShortcutBadgeException("No default launcher available");
|
||||
}
|
||||
|
||||
try {
|
||||
sShortcutBadger.executeBadge(context, sComponentName, badgeCount);
|
||||
} catch (Exception e) {
|
||||
throw new ShortcutBadgeException("Unable to execute badge", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to remove the notification count
|
||||
*
|
||||
* @param context Caller context
|
||||
* @return true in case of success, false otherwise
|
||||
*/
|
||||
public static boolean removeCount(Context context) {
|
||||
return applyCount(context, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to remove the notification count, throw a {@link ShortcutBadgeException} if it fails
|
||||
*
|
||||
* @param context Caller context
|
||||
*/
|
||||
public static void removeCountOrThrow(Context context) throws ShortcutBadgeException {
|
||||
applyCountOrThrow(context, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this platform launcher supports shortcut badges. Doing this check causes the side
|
||||
* effect of resetting the counter if it's supported, so this method should be followed by
|
||||
* a call that actually sets the counter to the desired value, if the counter is supported.
|
||||
*/
|
||||
public static boolean isBadgeCounterSupported(Context context) {
|
||||
// Checking outside synchronized block to avoid synchronization in the common case (flag
|
||||
// already set), and improve perf.
|
||||
if (sIsBadgeCounterSupported == null) {
|
||||
synchronized (sCounterSupportedLock) {
|
||||
// Checking again inside synch block to avoid setting the flag twice.
|
||||
if (sIsBadgeCounterSupported == null) {
|
||||
String lastErrorMessage = null;
|
||||
for (int i = 0; i < SUPPORTED_CHECK_ATTEMPTS; i++) {
|
||||
try {
|
||||
Log.i(LOG_TAG, "Checking if platform supports badge counters, attempt "
|
||||
+ String.format("%d/%d.", i + 1, SUPPORTED_CHECK_ATTEMPTS));
|
||||
if (initBadger(context)) {
|
||||
sShortcutBadger.executeBadge(context, sComponentName, 0);
|
||||
sIsBadgeCounterSupported = true;
|
||||
Log.i(LOG_TAG, "Badge counter is supported in this platform.");
|
||||
break;
|
||||
} else {
|
||||
lastErrorMessage = "Failed to initialize the badge counter.";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Keep retrying as long as we can. No need to dump the stack trace here
|
||||
// because this error will be the norm, not exception, for unsupported
|
||||
// platforms. So we just save the last error message to display later.
|
||||
lastErrorMessage = e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if (sIsBadgeCounterSupported == null) {
|
||||
Log.w(LOG_TAG, "Badge counter seems not supported for this platform: "
|
||||
+ lastErrorMessage);
|
||||
sIsBadgeCounterSupported = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sIsBadgeCounterSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context Caller context
|
||||
* @param notification
|
||||
* @param badgeCount
|
||||
*/
|
||||
public static void applyNotification(Context context, Notification notification, int badgeCount) {
|
||||
if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
|
||||
try {
|
||||
Field field = notification.getClass().getDeclaredField("extraNotification");
|
||||
Object extraNotification = field.get(notification);
|
||||
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
|
||||
method.invoke(extraNotification, badgeCount);
|
||||
} catch (Exception e) {
|
||||
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
|
||||
Log.d(LOG_TAG, "Unable to execute badge", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Badger if a launcher is availalble (eg. set as default on the device)
|
||||
// Returns true if a launcher is available, in this case, the Badger will be set and sShortcutBadger will be non null.
|
||||
private static boolean initBadger(Context context) {
|
||||
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
|
||||
if (launchIntent == null) {
|
||||
Log.e(LOG_TAG, "Unable to find launch intent for package " + context.getPackageName());
|
||||
return false;
|
||||
}
|
||||
|
||||
sComponentName = launchIntent.getComponent();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_HOME);
|
||||
List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
//Turns out framework does not guarantee to put DEFAULT Activity on top of the list.
|
||||
ResolveInfo resolveInfoDefault = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
validateInfoList(resolveInfoDefault, resolveInfos);
|
||||
|
||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
String currentHomePackage = resolveInfo.activityInfo.packageName;
|
||||
|
||||
for (Class<? extends Badger> badger : BADGERS) {
|
||||
Badger shortcutBadger = null;
|
||||
try {
|
||||
shortcutBadger = badger.newInstance();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (shortcutBadger != null && shortcutBadger.getSupportLaunchers().contains(currentHomePackage)) {
|
||||
if (isLauncherVersionSupported(context, currentHomePackage)) {
|
||||
sShortcutBadger = shortcutBadger;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sShortcutBadger != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sShortcutBadger == null) {
|
||||
if (Build.MANUFACTURER.equalsIgnoreCase("ZUK"))
|
||||
sShortcutBadger = new ZukHomeBadger();
|
||||
else if (Build.MANUFACTURER.equalsIgnoreCase("OPPO"))
|
||||
sShortcutBadger = new OPPOHomeBader();
|
||||
else if (Build.MANUFACTURER.equalsIgnoreCase("VIVO"))
|
||||
sShortcutBadger = new VivoHomeBadger();
|
||||
else if (Build.MANUFACTURER.equalsIgnoreCase("ZTE"))
|
||||
sShortcutBadger = new ZTEHomeBadger();
|
||||
else
|
||||
sShortcutBadger = new DefaultBadger();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Making sure that launcher version that yet doesn't support badges mechanism
|
||||
* is <b>NOT</b> used by <b><i>sShortcutBadger</i></b>.
|
||||
*/
|
||||
private static boolean isLauncherVersionSupported(Context context, String currentHomePackage) {
|
||||
if (!YandexLauncherBadger.PACKAGE_NAME.equals(currentHomePackage)) {
|
||||
return true;
|
||||
}
|
||||
return YandexLauncherBadger.isVersionSupported(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Making sure the default Home activity is on top of the returned list
|
||||
* @param defaultActivity default Home activity
|
||||
* @param resolveInfos list of all Home activities in the system
|
||||
*/
|
||||
private static void validateInfoList(ResolveInfo defaultActivity, List<ResolveInfo> resolveInfos) {
|
||||
int indexToSwapWith = 0;
|
||||
for (int i = 0, resolveInfosSize = resolveInfos.size(); i < resolveInfosSize; i++) {
|
||||
ResolveInfo resolveInfo = resolveInfos.get(i);
|
||||
String currentActivityName = resolveInfo.activityInfo.packageName;
|
||||
if (currentActivityName.equals(defaultActivity.activityInfo.packageName)) {
|
||||
indexToSwapWith = i;
|
||||
}
|
||||
}
|
||||
Collections.swap(resolveInfos, 0, indexToSwapWith);
|
||||
}
|
||||
|
||||
// Avoid anybody to instantiate this class
|
||||
private ShortcutBadger() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author Gernot Pansy
|
||||
*/
|
||||
public class AdwHomeBadger implements Badger {
|
||||
|
||||
public static final String INTENT_UPDATE_COUNTER = "org.adw.launcher.counter.SEND";
|
||||
public static final String PACKAGENAME = "PNAME";
|
||||
public static final String CLASSNAME = "CNAME";
|
||||
public static final String COUNT = "COUNT";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Intent intent = new Intent(INTENT_UPDATE_COUNTER);
|
||||
intent.putExtra(PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(CLASSNAME, componentName.getClassName());
|
||||
intent.putExtra(COUNT, badgeCount);
|
||||
|
||||
BroadcastHelper.sendIntentExplicitly(context, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"org.adw.launcher",
|
||||
"org.adwfreak.launcher"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author Gernot Pansy
|
||||
*/
|
||||
public class ApexHomeBadger implements Badger {
|
||||
|
||||
private static final String INTENT_UPDATE_COUNTER = "com.anddoes.launcher.COUNTER_CHANGED";
|
||||
private static final String PACKAGENAME = "package";
|
||||
private static final String COUNT = "count";
|
||||
private static final String CLASS = "class";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Intent intent = new Intent(INTENT_UPDATE_COUNTER);
|
||||
intent.putExtra(PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(COUNT, badgeCount);
|
||||
intent.putExtra(CLASS, componentName.getClassName());
|
||||
|
||||
BroadcastHelper.sendIntentExplicitly(context, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("com.anddoes.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author leolin
|
||||
*/
|
||||
public class AsusHomeBadger implements Badger {
|
||||
private static final String INTENT_ACTION = IntentConstants.DEFAULT_INTENT_ACTION;
|
||||
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";
|
||||
|
||||
private static final String PROVIDER_CONTENT_URI = "content://com.android.badge/"; // FIXME
|
||||
private static final String PROVIDER_COLUMNS_BADGE_COUNT = "badge_count"; // FIXME
|
||||
private static final String PROVIDER_COLUMNS_PACKAGE_NAME = "package_name"; // FIXME
|
||||
private static final String PROVIDER_COLUMNS_ACTIVITY_NAME = "activity_name"; // FIXME
|
||||
private static final String ASUS_LAUNCHER_PROVIDER_NAME = "com.android.badge";
|
||||
private final Uri BADGE_CONTENT_URI = Uri.parse(PROVIDER_CONTENT_URI);
|
||||
|
||||
private AsyncQueryHandler mQueryHandler;
|
||||
|
||||
// It seems that Asus handle Sony like badges better than old implementation...
|
||||
private static final String SONY_INTENT_ACTION = "com.sonyericsson.home.action.UPDATE_BADGE";
|
||||
private static final String SONY_INTENT_EXTRA_PACKAGE_NAME = "com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME";
|
||||
private static final String SONY_INTENT_EXTRA_ACTIVITY_NAME = "com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME";
|
||||
private static final String SONY_INTENT_EXTRA_MESSAGE = "com.sonyericsson.home.intent.extra.badge.MESSAGE";
|
||||
private static final String SONY_INTENT_EXTRA_SHOW_MESSAGE = "com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE";
|
||||
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
// FIXME: It seems that ZenUI (com.asus.launcher) declares a content provider for badges but without documentation it is hard to guess how to add badges with it. Current draft implementation gives "No yet implemented" exception.
|
||||
// if (asusBadgeContentProviderExists(context)) {
|
||||
// executeBadgeByContentProvider(context, componentName, badgeCount);
|
||||
// } else {
|
||||
executeBadgeByBroadcast(context, componentName, badgeCount);
|
||||
// }
|
||||
} else {
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
|
||||
intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
|
||||
intent.putExtra("badge_vip_count", 0);
|
||||
|
||||
BroadcastHelper.sendDefaultIntentExplicitly(context, intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeBadgeByBroadcast(Context context, ComponentName componentName, int badgeCount) {
|
||||
Intent intent = new Intent(SONY_INTENT_ACTION);
|
||||
intent.putExtra(SONY_INTENT_EXTRA_PACKAGE_NAME, componentName.getPackageName());
|
||||
intent.putExtra(SONY_INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
|
||||
intent.putExtra(SONY_INTENT_EXTRA_MESSAGE, String.valueOf(badgeCount));
|
||||
intent.putExtra(SONY_INTENT_EXTRA_SHOW_MESSAGE, badgeCount > 0);
|
||||
// FIXME: BroadcastHelper fail to resolve broadcast and then don't broadcast intent while it works.
|
||||
// BroadcastHelper.sendDefaultIntentExplicitly(context, intent);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("com.asus.launcher");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send request to Asus badge content provider to set badge in Sony home launcher.
|
||||
*
|
||||
* @param context the context to use
|
||||
* @param componentName the componentName to use
|
||||
* @param badgeCount the badge count
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
private void executeBadgeByContentProvider(Context context, ComponentName componentName,
|
||||
int badgeCount) {
|
||||
if (badgeCount < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ContentValues contentValues = createContentValues(badgeCount, componentName);
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
// We're in the main thread. Let's ensure the badge update happens in a background
|
||||
// thread by using an AsyncQueryHandler and an async update.
|
||||
if (mQueryHandler == null) {
|
||||
mQueryHandler = new AsyncQueryHandler(
|
||||
context.getApplicationContext().getContentResolver()) {
|
||||
};
|
||||
}
|
||||
insertBadgeAsync(contentValues);
|
||||
} else {
|
||||
// Already in a background thread. Let's update the badge synchronously. Otherwise,
|
||||
// if we use the AsyncQueryHandler, this thread may already be dead by the time the
|
||||
// async execution finishes, which will lead to an IllegalStateException.
|
||||
insertBadgeSync(context, contentValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously inserts the badge counter.
|
||||
*
|
||||
* @param contentValues Content values containing the badge count, package and activity names
|
||||
*/
|
||||
private void insertBadgeAsync(final ContentValues contentValues) {
|
||||
mQueryHandler.startInsert(0, null, BADGE_CONTENT_URI, contentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously inserts the badge counter.
|
||||
*
|
||||
* @param context Caller context
|
||||
* @param contentValues Content values containing the badge count, package and activity names
|
||||
*/
|
||||
private void insertBadgeSync(final Context context, final ContentValues contentValues) {
|
||||
context.getApplicationContext().getContentResolver()
|
||||
.insert(BADGE_CONTENT_URI, contentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ContentValues object to be used in the badge counter update. The package and
|
||||
* activity names must correspond to an activity that holds an intent filter with action
|
||||
* "android.intent.action.MAIN" and category android.intent.category.LAUNCHER" in the manifest.
|
||||
* Also, it is not allowed to publish badges on behalf of another client, so the package and
|
||||
* activity names must belong to the process from which the insert is made.
|
||||
* To be able to insert badges, the app must have the PROVIDER_INSERT_BADGE
|
||||
* permission in the manifest file. In case these conditions are not
|
||||
* fulfilled, or any content values are missing, there will be an unhandled
|
||||
* exception on the background thread.
|
||||
*
|
||||
* @param badgeCount the badge count
|
||||
* @param componentName the component name from which package and class name will be extracted
|
||||
*/
|
||||
private ContentValues createContentValues(final int badgeCount,
|
||||
final ComponentName componentName) {
|
||||
final ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(PROVIDER_COLUMNS_BADGE_COUNT, badgeCount);
|
||||
contentValues.put(PROVIDER_COLUMNS_PACKAGE_NAME, componentName.getPackageName());
|
||||
contentValues.put(PROVIDER_COLUMNS_ACTIVITY_NAME, componentName.getClassName());
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the latest Asus badge content provider exists.
|
||||
*
|
||||
* @param context the context to use
|
||||
* @return true if Asus badge content provider exists, otherwise false.
|
||||
*/
|
||||
private static boolean asusBadgeContentProviderExists(Context context) {
|
||||
boolean exists = false;
|
||||
ProviderInfo info = context.getPackageManager().resolveContentProvider(ASUS_LAUNCHER_PROVIDER_NAME, 0);
|
||||
if (info != null) {
|
||||
exists = true;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author leolin
|
||||
*/
|
||||
public class DefaultBadger implements Badger {
|
||||
private static final String INTENT_ACTION = IntentConstants.DEFAULT_INTENT_ACTION;
|
||||
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";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
|
||||
intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
|
||||
|
||||
BroadcastHelper.sendDefaultIntentExplicitly(context, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"fr.neamar.kiss",
|
||||
"com.quaap.launchtime",
|
||||
"com.quaap.launchtime_official"
|
||||
);
|
||||
}
|
||||
|
||||
boolean isSupported(Context context) {
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
return BroadcastHelper.resolveBroadcast(context, intent).size() > 0
|
||||
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& BroadcastHelper.resolveBroadcast(context, new Intent(IntentConstants.DEFAULT_OREO_INTENT_ACTION)).size() > 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Radko Roman
|
||||
* @since 13.04.17.
|
||||
*/
|
||||
public class EverythingMeHomeBadger implements Badger {
|
||||
|
||||
private static final String CONTENT_URI = "content://me.everything.badger/apps";
|
||||
private static final String COLUMN_PACKAGE_NAME = "package_name";
|
||||
private static final String COLUMN_ACTIVITY_NAME = "activity_name";
|
||||
private static final String COLUMN_COUNT = "count";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(COLUMN_PACKAGE_NAME, componentName.getPackageName());
|
||||
contentValues.put(COLUMN_ACTIVITY_NAME, componentName.getClassName());
|
||||
contentValues.put(COLUMN_COUNT, badgeCount);
|
||||
context.getContentResolver().insert(Uri.parse(CONTENT_URI), contentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("me.everything.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* @author Jason Ling
|
||||
*/
|
||||
public class HuaweiHomeBadger implements Badger {
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Bundle localBundle = new Bundle();
|
||||
localBundle.putString("package", context.getPackageName());
|
||||
localBundle.putString("class", componentName.getClassName());
|
||||
localBundle.putInt("badgenumber", badgeCount);
|
||||
context.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, localBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"com.huawei.android.launcher"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
public interface IntentConstants {
|
||||
String DEFAULT_INTENT_ACTION = "android.intent.action.BADGE_COUNT_UPDATE";
|
||||
String DEFAULT_OREO_INTENT_ACTION = "me.leolin.shortcutbadger.BADGE_COUNT_UPDATE";
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author Leo Lin
|
||||
* Deprecated, LG devices will use DefaultBadger
|
||||
*/
|
||||
@Deprecated
|
||||
public class LGHomeBadger implements Badger {
|
||||
|
||||
private static final String INTENT_ACTION = IntentConstants.DEFAULT_INTENT_ACTION;
|
||||
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";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
|
||||
intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
|
||||
|
||||
BroadcastHelper.sendDefaultIntentExplicitly(context, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"com.lge.launcher",
|
||||
"com.lge.launcher2"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* @author Leo Lin
|
||||
*/
|
||||
public class NewHtcHomeBadger implements Badger {
|
||||
|
||||
public static final String INTENT_UPDATE_SHORTCUT = "com.htc.launcher.action.UPDATE_SHORTCUT";
|
||||
public static final String INTENT_SET_NOTIFICATION = "com.htc.launcher.action.SET_NOTIFICATION";
|
||||
public static final String PACKAGENAME = "packagename";
|
||||
public static final String COUNT = "count";
|
||||
public static final String EXTRA_COMPONENT = "com.htc.launcher.extra.COMPONENT";
|
||||
public static final String EXTRA_COUNT = "com.htc.launcher.extra.COUNT";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
|
||||
Intent intent1 = new Intent(INTENT_SET_NOTIFICATION);
|
||||
boolean intent1Success;
|
||||
|
||||
intent1.putExtra(EXTRA_COMPONENT, componentName.flattenToShortString());
|
||||
intent1.putExtra(EXTRA_COUNT, badgeCount);
|
||||
|
||||
Intent intent = new Intent(INTENT_UPDATE_SHORTCUT);
|
||||
boolean intentSuccess;
|
||||
|
||||
intent.putExtra(PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(COUNT, badgeCount);
|
||||
|
||||
try {
|
||||
BroadcastHelper.sendIntentExplicitly(context, intent1);
|
||||
intent1Success = true;
|
||||
} catch (ShortcutBadgeException e) {
|
||||
intent1Success = false;
|
||||
}
|
||||
|
||||
try {
|
||||
BroadcastHelper.sendIntentExplicitly(context, intent);
|
||||
intentSuccess = true;
|
||||
} catch (ShortcutBadgeException e) {
|
||||
intentSuccess = false;
|
||||
}
|
||||
|
||||
if (!intent1Success && !intentSuccess) {
|
||||
throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Collections.singletonList("com.htc.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* Shortcut Badger support for Nova Launcher.
|
||||
* TeslaUnread must be installed.
|
||||
* User: Gernot Pansy
|
||||
* Date: 2014/11/03
|
||||
* Time: 7:15
|
||||
*/
|
||||
public class NovaHomeBadger implements Badger {
|
||||
|
||||
private static final String CONTENT_URI = "content://com.teslacoilsw.notifier/unread_count";
|
||||
private static final String COUNT = "count";
|
||||
private static final String TAG = "tag";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TAG, componentName.getPackageName() + "/" + componentName.getClassName());
|
||||
contentValues.put(COUNT, badgeCount);
|
||||
context.getContentResolver().insert(Uri.parse(CONTENT_URI), contentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("com.teslacoilsw.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
/**
|
||||
* Created by NingSo on 2016/10/14.上午10:09
|
||||
*
|
||||
* @author: NingSo
|
||||
* Email: ningso.ping@gmail.com
|
||||
*/
|
||||
|
||||
public class OPPOHomeBader implements Badger {
|
||||
|
||||
private static final String PROVIDER_CONTENT_URI = "content://com.android.badge/badge";
|
||||
private static final String INTENT_ACTION = "com.oppo.unsettledevent";
|
||||
private static final String INTENT_EXTRA_PACKAGENAME = "pakeageName";
|
||||
private static final String INTENT_EXTRA_BADGE_COUNT = "number";
|
||||
private static final String INTENT_EXTRA_BADGE_UPGRADENUMBER = "upgradeNumber";
|
||||
private static final String INTENT_EXTRA_BADGEUPGRADE_COUNT = "app_badge_count";
|
||||
private int mCurrentTotalCount = -1;
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
if (mCurrentTotalCount == badgeCount) {
|
||||
return;
|
||||
}
|
||||
mCurrentTotalCount = badgeCount;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
|
||||
executeBadgeByContentProvider(context, badgeCount);
|
||||
} else {
|
||||
executeBadgeByBroadcast(context, componentName, badgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Collections.singletonList("com.oppo.launcher");
|
||||
}
|
||||
|
||||
private void executeBadgeByBroadcast(Context context, ComponentName componentName,
|
||||
int badgeCount) throws ShortcutBadgeException {
|
||||
if (badgeCount == 0) {
|
||||
badgeCount = -1;
|
||||
}
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
|
||||
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
|
||||
intent.putExtra(INTENT_EXTRA_BADGE_UPGRADENUMBER, badgeCount);
|
||||
|
||||
BroadcastHelper.sendIntentExplicitly(context, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send request to OPPO badge content provider to set badge in OPPO home launcher.
|
||||
*
|
||||
* @param context the context to use
|
||||
* @param badgeCount the badge count
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
private void executeBadgeByContentProvider(Context context, int badgeCount) throws ShortcutBadgeException {
|
||||
try {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putInt(INTENT_EXTRA_BADGEUPGRADE_COUNT, badgeCount);
|
||||
context.getContentResolver().call(Uri.parse(PROVIDER_CONTENT_URI), "setAppBadgeCount", null, extras);
|
||||
} catch (Throwable ignored) {
|
||||
throw new ShortcutBadgeException("Unable to execute Badge By Content Provider");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.CloseHelper;
|
||||
|
||||
/**
|
||||
* @author Leo Lin
|
||||
*/
|
||||
public class SamsungHomeBadger implements Badger {
|
||||
private static final String CONTENT_URI = "content://com.sec.badge/apps?notify=true";
|
||||
private static final String[] CONTENT_PROJECTION = new String[]{"_id", "class"};
|
||||
|
||||
private DefaultBadger defaultBadger;
|
||||
|
||||
public SamsungHomeBadger() {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
defaultBadger = new DefaultBadger();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
if (defaultBadger != null && defaultBadger.isSupported(context)) {
|
||||
defaultBadger.executeBadge(context, componentName, badgeCount);
|
||||
} else {
|
||||
Uri mUri = Uri.parse(CONTENT_URI);
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = contentResolver.query(mUri, CONTENT_PROJECTION, "package=?", new String[]{componentName.getPackageName()}, null);
|
||||
if (cursor != null) {
|
||||
String entryActivityName = componentName.getClassName();
|
||||
boolean entryActivityExist = false;
|
||||
while (cursor.moveToNext()) {
|
||||
int id = cursor.getInt(0);
|
||||
ContentValues contentValues = getContentValues(componentName, badgeCount, false);
|
||||
contentResolver.update(mUri, contentValues, "_id=?", new String[]{String.valueOf(id)});
|
||||
if (entryActivityName.equals(cursor.getString(cursor.getColumnIndex("class")))) {
|
||||
entryActivityExist = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entryActivityExist) {
|
||||
ContentValues contentValues = getContentValues(componentName, badgeCount, true);
|
||||
contentResolver.insert(mUri, contentValues);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
CloseHelper.close(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContentValues getContentValues(ComponentName componentName, int badgeCount, boolean isInsert) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
if (isInsert) {
|
||||
contentValues.put("package", componentName.getPackageName());
|
||||
contentValues.put("class", componentName.getClassName());
|
||||
}
|
||||
|
||||
contentValues.put("badgecount", badgeCount);
|
||||
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"com.sec.android.app.launcher",
|
||||
"com.sec.android.app.twlauncher"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Leo Lin
|
||||
*/
|
||||
public class SonyHomeBadger implements Badger {
|
||||
|
||||
private static final String INTENT_ACTION = "com.sonyericsson.home.action.UPDATE_BADGE";
|
||||
private static final String INTENT_EXTRA_PACKAGE_NAME = "com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME";
|
||||
private static final String INTENT_EXTRA_ACTIVITY_NAME = "com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME";
|
||||
private static final String INTENT_EXTRA_MESSAGE = "com.sonyericsson.home.intent.extra.badge.MESSAGE";
|
||||
private static final String INTENT_EXTRA_SHOW_MESSAGE = "com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE";
|
||||
|
||||
private static final String PROVIDER_CONTENT_URI = "content://com.sonymobile.home.resourceprovider/badge";
|
||||
private static final String PROVIDER_COLUMNS_BADGE_COUNT = "badge_count";
|
||||
private static final String PROVIDER_COLUMNS_PACKAGE_NAME = "package_name";
|
||||
private static final String PROVIDER_COLUMNS_ACTIVITY_NAME = "activity_name";
|
||||
private static final String SONY_HOME_PROVIDER_NAME = "com.sonymobile.home.resourceprovider";
|
||||
private final Uri BADGE_CONTENT_URI = Uri.parse(PROVIDER_CONTENT_URI);
|
||||
|
||||
private AsyncQueryHandler mQueryHandler;
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName,
|
||||
int badgeCount) throws ShortcutBadgeException {
|
||||
if (sonyBadgeContentProviderExists(context)) {
|
||||
executeBadgeByContentProvider(context, componentName, badgeCount);
|
||||
} else {
|
||||
executeBadgeByBroadcast(context, componentName, badgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("com.sonyericsson.home", "com.sonymobile.home");
|
||||
}
|
||||
|
||||
private static void executeBadgeByBroadcast(Context context, ComponentName componentName,
|
||||
int badgeCount) {
|
||||
Intent intent = new Intent(INTENT_ACTION);
|
||||
intent.putExtra(INTENT_EXTRA_PACKAGE_NAME, componentName.getPackageName());
|
||||
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
|
||||
intent.putExtra(INTENT_EXTRA_MESSAGE, String.valueOf(badgeCount));
|
||||
intent.putExtra(INTENT_EXTRA_SHOW_MESSAGE, badgeCount > 0);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send request to Sony badge content provider to set badge in Sony home launcher.
|
||||
*
|
||||
* @param context the context to use
|
||||
* @param componentName the componentName to use
|
||||
* @param badgeCount the badge count
|
||||
*/
|
||||
private void executeBadgeByContentProvider(Context context, ComponentName componentName,
|
||||
int badgeCount) {
|
||||
if (badgeCount < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ContentValues contentValues = createContentValues(badgeCount, componentName);
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
// We're in the main thread. Let's ensure the badge update happens in a background
|
||||
// thread by using an AsyncQueryHandler and an async update.
|
||||
if (mQueryHandler == null) {
|
||||
mQueryHandler = new AsyncQueryHandler(
|
||||
context.getApplicationContext().getContentResolver()) {
|
||||
};
|
||||
}
|
||||
insertBadgeAsync(contentValues);
|
||||
} else {
|
||||
// Already in a background thread. Let's update the badge synchronously. Otherwise,
|
||||
// if we use the AsyncQueryHandler, this thread may already be dead by the time the
|
||||
// async execution finishes, which will lead to an IllegalStateException.
|
||||
insertBadgeSync(context, contentValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously inserts the badge counter.
|
||||
*
|
||||
* @param contentValues Content values containing the badge count, package and activity names
|
||||
*/
|
||||
private void insertBadgeAsync(final ContentValues contentValues) {
|
||||
mQueryHandler.startInsert(0, null, BADGE_CONTENT_URI, contentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously inserts the badge counter.
|
||||
*
|
||||
* @param context Caller context
|
||||
* @param contentValues Content values containing the badge count, package and activity names
|
||||
*/
|
||||
private void insertBadgeSync(final Context context, final ContentValues contentValues) {
|
||||
context.getApplicationContext().getContentResolver()
|
||||
.insert(BADGE_CONTENT_URI, contentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ContentValues object to be used in the badge counter update. The package and
|
||||
* activity names must correspond to an activity that holds an intent filter with action
|
||||
* "android.intent.action.MAIN" and category android.intent.category.LAUNCHER" in the manifest.
|
||||
* Also, it is not allowed to publish badges on behalf of another client, so the package and
|
||||
* activity names must belong to the process from which the insert is made.
|
||||
* To be able to insert badges, the app must have the PROVIDER_INSERT_BADGE
|
||||
* permission in the manifest file. In case these conditions are not
|
||||
* fulfilled, or any content values are missing, there will be an unhandled
|
||||
* exception on the background thread.
|
||||
*
|
||||
* @param badgeCount the badge count
|
||||
* @param componentName the component name from which package and class name will be extracted
|
||||
*
|
||||
*/
|
||||
private ContentValues createContentValues(final int badgeCount,
|
||||
final ComponentName componentName) {
|
||||
final ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(PROVIDER_COLUMNS_BADGE_COUNT, badgeCount);
|
||||
contentValues.put(PROVIDER_COLUMNS_PACKAGE_NAME, componentName.getPackageName());
|
||||
contentValues.put(PROVIDER_COLUMNS_ACTIVITY_NAME, componentName.getClassName());
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the latest Sony badge content provider exists .
|
||||
*
|
||||
* @param context the context to use
|
||||
* @return true if Sony badge content provider exists, otherwise false.
|
||||
*/
|
||||
private static boolean sonyBadgeContentProviderExists(Context context) {
|
||||
boolean exists = false;
|
||||
ProviderInfo info = context.getPackageManager().resolveContentProvider(SONY_HOME_PROVIDER_NAME, 0);
|
||||
if (info != null) {
|
||||
exists = true;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* @author leolin
|
||||
*/
|
||||
public class VivoHomeBadger implements Badger {
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Intent intent = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
|
||||
intent.putExtra("packageName", context.getPackageName());
|
||||
intent.putExtra("className", componentName.getClassName());
|
||||
intent.putExtra("notificationNum", badgeCount);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList("com.vivo.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.util.BroadcastHelper;
|
||||
|
||||
|
||||
/**
|
||||
* @author leolin
|
||||
*/
|
||||
@Deprecated
|
||||
public class XiaomiHomeBadger implements Badger {
|
||||
|
||||
public static final String INTENT_ACTION = "android.intent.action.APPLICATION_MESSAGE_UPDATE";
|
||||
public static final String EXTRA_UPDATE_APP_COMPONENT_NAME = "android.intent.extra.update_application_component_name";
|
||||
public static final String EXTRA_UPDATE_APP_MSG_TEXT = "android.intent.extra.update_application_message_text";
|
||||
private ResolveInfo resolveInfo;
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
try {
|
||||
Class miuiNotificationClass = Class.forName("android.app.MiuiNotification");
|
||||
Object miuiNotification = miuiNotificationClass.newInstance();
|
||||
Field field = miuiNotification.getClass().getDeclaredField("messageCount");
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(miuiNotification, String.valueOf(badgeCount == 0 ? "" : badgeCount));
|
||||
} catch (Exception e) {
|
||||
field.set(miuiNotification, badgeCount);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Intent localIntent = new Intent(
|
||||
INTENT_ACTION);
|
||||
localIntent.putExtra(EXTRA_UPDATE_APP_COMPONENT_NAME, componentName.getPackageName() + "/" + componentName.getClassName());
|
||||
localIntent.putExtra(EXTRA_UPDATE_APP_MSG_TEXT, String.valueOf(badgeCount == 0 ? "" : badgeCount));
|
||||
|
||||
try {
|
||||
BroadcastHelper.sendIntentExplicitly(context, localIntent);
|
||||
} catch (ShortcutBadgeException ignored) {}
|
||||
}
|
||||
if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
|
||||
tryNewMiuiBadge(context, badgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
private void tryNewMiuiBadge(Context context, int badgeCount) throws ShortcutBadgeException {
|
||||
if (resolveInfo == null) {
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_HOME);
|
||||
resolveInfo = context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
}
|
||||
|
||||
if (resolveInfo != null) {
|
||||
NotificationManager mNotificationManager = (NotificationManager) context
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
Notification.Builder builder = new Notification.Builder(context)
|
||||
.setContentTitle("")
|
||||
.setContentText("")
|
||||
.setSmallIcon(resolveInfo.getIconResource());
|
||||
Notification notification = builder.build();
|
||||
try {
|
||||
Field field = notification.getClass().getDeclaredField("extraNotification");
|
||||
Object extraNotification = field.get(notification);
|
||||
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
|
||||
method.invoke(extraNotification, badgeCount);
|
||||
mNotificationManager.notify(0, notification);
|
||||
} catch (Exception e) {
|
||||
throw new ShortcutBadgeException("not able to set badge", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Arrays.asList(
|
||||
"com.miui.miuilite",
|
||||
"com.miui.home",
|
||||
"com.miui.miuihome",
|
||||
"com.miui.miuihome2",
|
||||
"com.miui.mihome",
|
||||
"com.miui.mihome2",
|
||||
"com.i.miui.launcher"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* @author Nikolay Pakhomov
|
||||
* created 16/04/2018
|
||||
*/
|
||||
public class YandexLauncherBadger implements Badger {
|
||||
|
||||
public static final String PACKAGE_NAME = "com.yandex.launcher";
|
||||
|
||||
private static final String AUTHORITY = "com.yandex.launcher.badges_external";
|
||||
private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
|
||||
private static final String METHOD_TO_CALL = "setBadgeNumber";
|
||||
|
||||
private static final String COLUMN_CLASS = "class";
|
||||
private static final String COLUMN_PACKAGE = "package";
|
||||
private static final String COLUMN_BADGES_COUNT = "badges_count";
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(COLUMN_CLASS, componentName.getClassName());
|
||||
extras.putString(COLUMN_PACKAGE, componentName.getPackageName());
|
||||
extras.putString(COLUMN_BADGES_COUNT, String.valueOf(badgeCount));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
context.getContentResolver().call(CONTENT_URI, METHOD_TO_CALL, null, extras);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isVersionSupported(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
try {
|
||||
context.getContentResolver().call(CONTENT_URI, "", null, null);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Collections.singletonList(PACKAGE_NAME);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
public class ZTEHomeBadger implements Badger {
|
||||
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount)
|
||||
throws ShortcutBadgeException {
|
||||
Bundle extra = new Bundle();
|
||||
extra.putInt("app_badge_count", badgeCount);
|
||||
extra.putString("app_badge_component_name", componentName.flattenToString());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
context.getContentResolver().call(
|
||||
Uri.parse("content://com.android.launcher3.cornermark.unreadbadge"),
|
||||
"setAppUnreadCount", null, extra);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package me.leolin.shortcutbadger.impl;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.Badger;
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
|
||||
/**
|
||||
* Created by wuxuejian on 2016/10/9.
|
||||
* 需在设置 -- 通知和状态栏 -- 应用角标管理 中开启应用
|
||||
*/
|
||||
|
||||
public class ZukHomeBadger implements Badger {
|
||||
|
||||
private final Uri CONTENT_URI = Uri.parse("content://com.android.badge/badge");
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
@Override
|
||||
public void executeBadge(Context context, ComponentName componentName, int badgeCount) throws ShortcutBadgeException {
|
||||
Bundle extra = new Bundle();
|
||||
extra.putInt("app_badge_count", badgeCount);
|
||||
context.getContentResolver().call(CONTENT_URI, "setAppBadgeCount", null, extra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSupportLaunchers() {
|
||||
return Collections.singletonList("com.zui.launcher");
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package me.leolin.shortcutbadger.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.leolin.shortcutbadger.ShortcutBadgeException;
|
||||
import me.leolin.shortcutbadger.impl.IntentConstants;
|
||||
|
||||
/**
|
||||
* Created by mahijazi on 17/05/16.
|
||||
*/
|
||||
public class BroadcastHelper {
|
||||
|
||||
public static List<ResolveInfo> resolveBroadcast(Context context, Intent intent) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
|
||||
|
||||
return receivers != null ? receivers : Collections.<ResolveInfo>emptyList();
|
||||
}
|
||||
|
||||
public static void sendIntentExplicitly(Context context, Intent intent) throws ShortcutBadgeException {
|
||||
List<ResolveInfo> resolveInfos = resolveBroadcast(context, intent);
|
||||
|
||||
if (resolveInfos.size() == 0) {
|
||||
throw new ShortcutBadgeException("unable to resolve intent: " + intent.toString());
|
||||
}
|
||||
|
||||
for (ResolveInfo info : resolveInfos) {
|
||||
Intent actualIntent = new Intent(intent);
|
||||
|
||||
if (info != null) {
|
||||
actualIntent.setPackage(info.resolvePackageName);
|
||||
context.sendBroadcast(actualIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendDefaultIntentExplicitly(Context context, Intent intent) throws ShortcutBadgeException {
|
||||
boolean oreoIntentSuccess = false;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Intent oreoIntent = new Intent(intent);
|
||||
|
||||
oreoIntent.setAction(IntentConstants.DEFAULT_OREO_INTENT_ACTION);
|
||||
|
||||
try {
|
||||
sendIntentExplicitly(context, oreoIntent);
|
||||
oreoIntentSuccess = true;
|
||||
} catch (ShortcutBadgeException e) {
|
||||
oreoIntentSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (oreoIntentSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
// try pre-Oreo default intent
|
||||
sendIntentExplicitly(context, intent);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package me.leolin.shortcutbadger.util;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author leolin
|
||||
*/
|
||||
public class CloseHelper {
|
||||
|
||||
public static void close(Cursor cursor) {
|
||||
if (cursor != null && !cursor.isClosed()) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void closeQuietly(Closeable closeable) {
|
||||
try {
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
} catch (IOException var2) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue