package com.solderbyte.openfit; import java.util.ArrayList; import java.util.List; import com.solderbyte.openfit.util.OpenFitIntent; import android.app.ActivityManager; import android.app.Notification; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Bundle; import android.os.Process; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.RemoteViews; import android.widget.TextView; public class NotificationService extends NotificationListenerService { private static final String LOG_TAG = "OpenFit:NotificationService"; private ArrayList<String> ListPackageNames = new ArrayList<String>(); private PackageManager packageManager = null; private Context context; // view data private String NOTIFICATION_TITLE = null; private String NOTIFICATION_TEXT = null; private String NOTIFICATION_BIG_TEXT = null; // applications private String APP_FB_MESSENGER = "com.facebook.orca"; private String APP_WHATSAPP = "com.whatsapp"; private String APP_G_HANGOUTS = "com.google.android.talk"; @Override public void onCreate() { Log.d(LOG_TAG, "Created NotificationService"); this.registerReceiver(serviceStopReceiver, new IntentFilter(OpenFitIntent.INTENT_SERVICE_STOP)); this.registerReceiver(applicationsReceiver, new IntentFilter(OpenFitIntent.INTENT_SERVICE_NOTIFICATION_APPLICATIONS)); context = getApplicationContext(); packageManager = this.getPackageManager(); this.checkNotificationListenerService(); Intent msg = new Intent(OpenFitIntent.INTENT_SERVICE_NOTIFICATION); context.sendBroadcast(msg); super.onCreate(); } @Override public void onNotificationPosted(StatusBarNotification sbn) { Log.d(LOG_TAG, "onNotificationPosted"); String packageName = sbn.getPackageName(); String appName = this.getAppName(packageName); if(!ListPackageNames.contains(packageName)) { Log.d(LOG_TAG, "filtered by list"); return; } // API v19 Notification notification = sbn.getNotification(); Bundle extras = notification.extras; this.getViewNotification(notification, packageName); //String category = notification.category; API v21 if((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) { Log.d(LOG_TAG, "filtered by flags"); return; } String ticker = null; String message = null; String submessage = null; String summary = null; String info = null; String title = null; try { ticker = (String) sbn.getNotification().tickerText; } catch(Exception e) { Log.d(LOG_TAG, "Notification does not have tickerText"); } String tag = sbn.getTag(); long time = sbn.getPostTime(); int id = sbn.getId(); if(extras.getCharSequence("android.title") != null) { title = extras.getString("android.title"); } if(extras.getCharSequence("android.text") != null) { message = extras.getCharSequence("android.text").toString(); } if(extras.getCharSequence("android.subText") != null) { submessage = extras.getCharSequence("android.subText").toString(); } if(extras.getCharSequence("android.summaryText") != null) { summary = extras.getCharSequence("android.summaryText").toString(); } if(extras.getCharSequence("android.infoText") != null) { info = extras.getCharSequence("android.infoText").toString(); } if(extras.getCharSequence("android.infoText") != null) { info = extras.getCharSequence("android.infoText").toString(); } Log.d(LOG_TAG, "Captured notification message: " + message + " from source:" + packageName); Log.d(LOG_TAG, "ticker: " + ticker); Log.d(LOG_TAG, "title: " + title); Log.d(LOG_TAG, "message: " + message); Log.d(LOG_TAG, "tag: " + tag); Log.d(LOG_TAG, "time: " + time); Log.d(LOG_TAG, "id: " + id); Log.d(LOG_TAG, "submessage: " + submessage); Log.d(LOG_TAG, "summary: " + summary); Log.d(LOG_TAG, "info: " + info); Log.d(LOG_TAG, "view title: " + NOTIFICATION_TITLE); Log.d(LOG_TAG, "view big text: " + NOTIFICATION_BIG_TEXT); Log.d(LOG_TAG, "view text: " + NOTIFICATION_TEXT); String APP_NAME = appName; String PACKAGE_NAME = packageName; String NAME = null; String CONTACT = null; String GROUP = null; String MESSAGE = null; int ID = id; long CREATED = time; if(packageName.equals(APP_FB_MESSENGER)) { // facebook messenger // appName: Messenger // packageName: com.facebook.orca // name: title or view title // contact: n/a // message: message or view big text if(title != null) { NAME = title; } else { NAME = NOTIFICATION_TITLE; } if(message != null) { MESSAGE = message; } else if(NOTIFICATION_BIG_TEXT != null) { MESSAGE = NOTIFICATION_BIG_TEXT; } else { MESSAGE = NOTIFICATION_TEXT; } } else if(packageName.equals(APP_G_HANGOUTS)) { // google hangouts // appName: Hangouts // packageName: com.google.android.talk // name: title or view title (name) // contact: summary or view text (email) // message: message or view big text if(title != null) { NAME = title; } else { NAME = NOTIFICATION_TITLE; } if(summary != null) { CONTACT = summary; } else { CONTACT = NOTIFICATION_TEXT; } if(message != null) { MESSAGE = message; } else { MESSAGE = NOTIFICATION_BIG_TEXT; } } else if(packageName.equals(APP_WHATSAPP)) { // whatsapp // appName: WhatsApp // packageName: com.whatsapp // name: title or view title (group: name @ group) // contact: n/a // message: message or view text big text try { if(message.matches(".*(\\d+).new messages.*") || NOTIFICATION_TEXT.matches(".*(\\d+).new messages.*")) { Log.d(LOG_TAG, "ignoring message"); return; } } catch(Exception e) { Log.w(LOG_TAG, "regex error: " + e.getMessage()); } String[] split; if(title != null) { // group message if(title.contains("@")) { split = title.split("(.+)@(.+)"); NAME = split[0]; GROUP = split[1]; } else { NAME = title; } } else if(NOTIFICATION_TITLE != null) { if(title.contains("@")) { split = NOTIFICATION_TITLE.split("(.+)@(.+)"); NAME = split[0]; GROUP = split[1]; } else { NAME = NOTIFICATION_TITLE; } } else { NAME = title; } if(NOTIFICATION_BIG_TEXT != null) { MESSAGE = NOTIFICATION_BIG_TEXT; } else if(NOTIFICATION_TEXT != null) { MESSAGE = NOTIFICATION_TEXT; } else { MESSAGE = message; } } else { if(title != null) { NAME = title; } else { NAME = NOTIFICATION_TITLE; } if(NOTIFICATION_BIG_TEXT != null) { MESSAGE = NOTIFICATION_BIG_TEXT; } else if(message != null) { MESSAGE = message; } else { MESSAGE = NOTIFICATION_TEXT; } } Intent msg = new Intent(OpenFitIntent.INTENT_NOTIFICATION); msg.putExtra("packageName", packageName); msg.putExtra("ticker", ticker); msg.putExtra("title", NAME); msg.putExtra("message", MESSAGE); //msg.putExtra("title", title); //msg.putExtra("message", message); msg.putExtra("time", time); msg.putExtra("id", id); if(submessage != null) { msg.putExtra("submessage", submessage); } context.sendBroadcast(msg); Log.d(LOG_TAG, "Sending notification message: " + message + " from source:" + packageName); } @Override public void onNotificationRemoved(StatusBarNotification sbn) { Log.d(LOG_TAG, "onNotificationRemoved"); String packageName = sbn.getPackageName(); String shortMsg = ""; try { shortMsg = (String) sbn.getNotification().tickerText; } catch(Exception e) { } Log.d(LOG_TAG, "Removed notification message: " + shortMsg + " from source:" + packageName); } public void checkNotificationListenerService() { Log.d(LOG_TAG, "checkNotificationListenerService"); boolean isNotificationListenerRunning = false; ComponentName thisComponent = new ComponentName(this, NotificationService.class); ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> runningServices = manager.getRunningServices(Integer.MAX_VALUE); if(runningServices == null) { Log.d(LOG_TAG, "running services is null"); return; } for(ActivityManager.RunningServiceInfo service : runningServices) { if(service.service.equals(thisComponent)) { Log.d(LOG_TAG, "checkNotificationListenerService service - pid: " + service.pid + ", currentPID: " + Process.myPid() + ", clientPackage: " + service.clientPackage + ", clientCount: " + service.clientCount + ", clientLabel: " + ((service.clientLabel == 0) ? "0" : "(" + getResources().getString(service.clientLabel) + ")")); if(service.pid == Process.myPid() /*&& service.clientCount > 0 && !TextUtils.isEmpty(service.clientPackage)*/) { isNotificationListenerRunning = true; } } } if(isNotificationListenerRunning) { Log.d(LOG_TAG, "NotificationListenerService is running"); return; } Log.d(LOG_TAG, "NotificationListenerService is not running, trying to start"); this.toggleNotificationListenerService(); } public void toggleNotificationListenerService() { Log.d(LOG_TAG, "toggleNotificationListenerService"); // adb shell dumpsys notification // force start of notification service ComponentName thisComponent = new ComponentName(this, NotificationService.class); packageManager.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); packageManager.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } public void setPackageNames(ArrayList<String> packageNames) { ListPackageNames = packageNames; } public String getAppName(String packageName) { if(packageName == null) { return null; } ApplicationInfo appInfo = null; try { appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { Log.d(LOG_TAG, "Cannot get application info"); } String appName = (String) packageManager.getApplicationLabel(appInfo); return appName; } public boolean getViewNotification(Notification n, String packageName) { Log.d(LOG_TAG, "getViewNotification"); if(packageName == null) { return false; } Resources resources = null; try { resources = packageManager.getResourcesForApplication(packageName); } catch(Exception e){ Log.e(LOG_TAG, "Failed to get PackageManager: " + e.getMessage()); } if(resources == null) { Log.e(LOG_TAG, "No PackageManager resources"); return false; } int TITLE = resources.getIdentifier("android:id/title", null, null); int BIG_TEXT = resources.getIdentifier("android:id/big_text", null, null); int TEXT = resources.getIdentifier("android:id/text", null, null); RemoteViews views = n.bigContentView; if(views == null) { views = n.contentView; } if(views == null) { Log.d(LOG_TAG, "No RemoteViews"); return false; } LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup localView = null; try { localView = (ViewGroup) inflater.inflate(views.getLayoutId(), null); views.reapply(context, localView); } catch(Exception e) { Log.e(LOG_TAG, "Error with local view: " + e.getMessage()); return false; } Log.d(LOG_TAG, "about to get views"); TextView title = (TextView) localView.findViewById(TITLE); if(title != null) { NOTIFICATION_TITLE = title.getText().toString(); } else { NOTIFICATION_TITLE = null; } TextView big = (TextView) localView.findViewById(BIG_TEXT); if(big != null) { NOTIFICATION_BIG_TEXT = big.getText().toString(); } else { NOTIFICATION_BIG_TEXT = null; } TextView text = (TextView) localView.findViewById(TEXT); if(text != null) { NOTIFICATION_TEXT = text.getText().toString(); } else { NOTIFICATION_TEXT = null; } return true; } private BroadcastReceiver serviceStopReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "Stopping Service"); unregisterReceiver(applicationsReceiver); unregisterReceiver(serviceStopReceiver); stopSelf(); } }; private BroadcastReceiver applicationsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { ArrayList<String> applications = intent.getStringArrayListExtra(OpenFitIntent.INTENT_EXTRA_DATA); setPackageNames(applications); Log.d(LOG_TAG, "Recieved listeningApps: " + applications.size()); } }; }