text: 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;
      }
  }
  