Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Michal Tajchert] Hijacking your notifications

[Michal Tajchert] Hijacking your notifications

Presentation from GDG DevFest Ukraine 2015 - the biggest Google related event in the country. October 23-24, Lviv. Learn more at http://devfest.gdg.org.ua/

Google Developers Group Lviv

October 24, 2015
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Programming

Transcript

  1. #dfua Default - is not enough NotificationCompat.Builder mBuilder = new

    NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_launcher) .setContentTitle("My notification"); mBuilder.setDefaults(Notification.DEFAULT_ALL); Android 4.2 - SecurityException
  2. #dfua Pro Tip - BackStackBuilder NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)

    .setSmallIcon(R.drawable.ic_launcher) .setContentTitle("My notification"); TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); stackBuilder.addNextIntent(new Intent(context, ActivityMain.class)); stackBuilder.addNextIntent(new Intent(context, ActivityMain.class)); stackBuilder.addNextIntent(new Intent(context, ActivityMain.class)); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); mBuilder.setContentIntent(resultPendingIntent);
  3. #dfua Check and enable notification access if (!Settings.Secure.getString(getContentResolver(),"enabled_notification_listeners") .contains(getApplicationContext().getPackageName())) {

    //service is not enabled - try to enabled getApplicationContext().startActivity( new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS") .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); }
  4. #dfua Listener Service ENTER FILENAME/LANG public class NotificationReceiver extends NotificationListenerService

    { @Override public void onNotificationPosted(StatusBarNotification statusBarNotification) {} @Override public void onNotificationRemoved(StatusBarNotification statusBarNotification) {} ... }
  5. #dfua What it allows us to? • StatusBarNotification ◦ getId

    ◦ getTag ◦ getKey + getGroupKey ◦ isOngoing + isClarable ◦ getPackage + getPostTime + getUser etc. ◦ clone and cloneLight ◦ getNotification :)
  6. #dfua Where the fun begins Bundle bundle = statusBarNotification.getNotification().extras; for

    (String key : bundle.keySet()) { Object value = bundle.get(key); if("android.wearable.EXTENSIONS".equals(key)){ Bundle wearBundle = ((Bundle) value); for (String keyInner : wearBundle.keySet()) { Object valueInner = wearBundle.get(keyInner); if(keyInner != null && valueInner != null){ if("actions".equals(keyInner) && valueInner instanceof ArrayList){ ArrayList<Notification.Action> actions = new ArrayList<>(); actions.addAll((ArrayList) valueInner); for(Notification.Action act : actions) { if (act.getRemoteInputs() != null) {//API > 20 needed android.app.RemoteInput[] remoteInputs = act.getRemoteInputs(); }}}}}}}
  7. #dfua Where the fun begins - fixed WearableExtender wearableExtender =

    new WearableExtender(statusBarNotification.getNotification()); List<Action> actions = wearableExtender.getActions(); for(Action act : actions) { if(act != null && act.getRemoteInputs() != null) { remoteInputs.addAll(Arrays.asList(act.getRemoteInputs())); } }
  8. #dfua Fill RemoteInputs and send back Intent localIntent = new

    Intent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Bundle localBundle = notificationWear.bundle; for(RemoteInput remoteIn : remoteInputs){ localBundle.putCharSequence(remoteIn.getResultKey(), "Our answer here"); } RemoteInput.addResultsToIntent(remoteInputs, localIntent, localBundle); pendingIntent.send(MainActivity.this, 0, localIntent);
  9. #dfua Small tricks String label = remoteInput.getLabel().toString(); Boolean canFreeForm =

    remoteInput.getAllowFreeFormInput(); CharSequence[] choices = remoteInput.getChoices();