NotificationListenerService and kitkat

Android 4.3 (API 18) introduced NotificationListenerService.
I published a post about it a few months ago.

Android 4.4 (API 19) added new features, and now we can have a lot of extra info about a notification (before we need to use reflection to read some info).

As in 4.3,to use the NotificationListenerService we have to extend the NotificationListenerService and implement onNotificationPosted() and onNotificationRemoved() methods
public class SimpleKitkatNotificationListener extends NotificationListenerService {

        @Override
        public void onNotificationPosted(StatusBarNotification sbn) {
              //..............
        }

        @Override
        public void onNotificationRemoved(StatusBarNotification sbn) {
              //.............. 
        }
}
Then we must declare the service in the manifest file with the BIND_NOTIFICATION_LISTENER_SERVICE permission and include an intent filter with the SERVICE_INTERFACE action

 <service
      android:name="it.gmariotti.android.examples.
            notificationlistener.SimpleKitkatNotificationListener"
      android:label="@string/service_name"
      android:debuggable="true"
      android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
      <intent-filter>
           <action android:name="android.service.
                 notification.NotificationListenerService" />
      </intent-filter>

 </service>
Finally user must enable the service. Without this authorization it doesn't work!
You can find it in "Settings" -> "Security" -> "Notification access".
You should provide an Intent to help your users :
    Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
    startActivity(intent);
Android 4.4 introduced a new Notification.extras field which includes a Bundle with additional metadata.
It is very easy to use:
   Notification mNotification=sbn.getNotification();
   Bundle extras = mNotification.extras;
This Bundle can contain a lot of info. You can find the keys in Notification class. Some of these are:
   /**
     * {@link #extras} key: this is the title of the notification,
     * as supplied to {@link Builder#setContentTitle(CharSequence)}.
     */
    public static final String EXTRA_TITLE = "android.title";

    /**
     * {@link #extras} key: this is the main text payload, as supplied to
     * {@link Builder#setContentText(CharSequence)}.
     */
    public static final String EXTRA_TEXT = "android.text";

    /**
     * {@link #extras} key: this is a third line of text, as supplied to
     * {@link Builder#setSubText(CharSequence)}.
     */
    public static final String EXTRA_SUB_TEXT = "android.subText";

    /**
     * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the
     * notification payload, as
     * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
     */
    public static final String EXTRA_LARGE_ICON = "android.largeIcon";

I tried with a Hangouts Message:

Bundle[
     {android.title=Gabriele Mariotti, 
      android.subText=null, 
      android.showChronometer=false, 
      android.icon=2130838949, 
      android.text=Send a message with Hangouts,
      android.progress=0, 
      android.progressMax=0, 
      android.showWhen=true, 
      android.largeIcon=android.graphics.Bitmap@42075010, 
      android.infoText=null, 
      android.progressIndeterminate=false, 
      android.scoreModified=false}]

You can easily get these data.
     String notificationTitle = extras.getString(Notification.EXTRA_TITLE);
     int notificationIcon = extras.getInt(Notification.EXTRA_SMALL_ICON);
     Bitmap notificationLargeIcon = 
                  ((Bitmap) extras.getParcelable(Notification.EXTRA_LARGE_ICON));
     CharSequence notificationText = extras.getCharSequence(Notification.EXTRA_TEXT);
     CharSequence notificationSubText = extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
Also you can display them... and yes, you can get also the BigPicture (if exists).



I tried with an email:

Bundle[
     {android.title=Gabriele Mariotti,
      android.subText=email@xxxx.com, 
      android.showChronometer=false, 
      android.icon=2130837697, 
      android.text=A simple subject \n A simple text, 
      android.progress=0,
      android.progressMax=0,
      android.showWhen=true,
      android.largeIcon=android.graphics.Bitmap@4208ba28,
      android.infoText=null,
      android.progressIndeterminate=false,
      android.scoreModified=false}
]

In this way you can have a lot of info which required a reflection in 4.3.
It is time to update the apps which use a Notification Listener.

Here the code:
public class SimpleKitkatNotificationListener extends NotificationListenerService {

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        Notification mNotification=sbn.getNotification();
        if (mNotification!=null){
            Bundle extras = mNotification.extras;

            Intent intent = new Intent(MainActivity.INTENT_ACTION_NOTIFICATION);
            intent.putExtras(mNotification.extras);
            sendBroadcast(intent);

        }
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {

    }
}
public class MainActivity extends Activity {

    protected MyReceiver mReceiver = new MyReceiver();
    public static String INTENT_ACTION_NOTIFICATION = "it.gmariotti.notification";

    protected TextView title;
    protected TextView text;
    protected TextView subtext;
    protected ImageView largeIcon;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Retrieve ui elements
        title = (TextView) findViewById(R.id.nt_title);
        text = (TextView) findViewById(R.id.nt_text);
        subtext = (TextView) findViewById(R.id.nt_subtext);
        largeIcon = (ImageView) findViewById(R.id.nt_largeicon);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_autorize:
                Intent intent = new Intent
                ("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
                startActivity(intent);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mReceiver == null) mReceiver = new MyReceiver();
        registerReceiver(mReceiver, new IntentFilter(INTENT_ACTION_NOTIFICATION));
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mReceiver);
    }

    public class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent != null) {
                Bundle extras = intent.getExtras();
                String notificationTitle = 
                          extras.getString(Notification.EXTRA_TITLE);
                Bitmap notificationLargeIcon =
                          ((Bitmap) extras.getParcelable(Notification.EXTRA_LARGE_ICON));
                CharSequence notificationText = 
                          extras.getCharSequence(Notification.EXTRA_TEXT);
                CharSequence notificationSubText = 
                          extras.getCharSequence(Notification.EXTRA_SUB_TEXT);

                title.setText(notificationTitle);
                text.setText(notificationText);
                subtext.setText(notificationSubText);

                if (notificationLargeIcon != null) {
                    largeIcon.setImageBitmap(notificationLargeIcon);
                }
            }

        }
    }
}

You can get code from GitHub:

Popular posts from this blog

Expand and collapse animation

How to centralize the support libraries dependencies in gradle

Android-5: Card and images with rounded corners in Android 4