First commit
This commit is contained in:
commit
29f9e8ddab
|
@ -0,0 +1,3 @@
|
||||||
|
= 0.0.1 =
|
||||||
|
|
||||||
|
In progress
|
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2015 Javier Rengel (Coconauts)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,72 @@
|
||||||
|
# NotificationListenerService plugin for Cordova
|
||||||
|
|
||||||
|
This is an implementation of the
|
||||||
|
[NotificationListenerService in Android](https://developer.android.com/reference/android/service/notification/NotificationListenerService.html)
|
||||||
|
for Cordova.
|
||||||
|
|
||||||
|
A service that receives calls from the system when new notifications are posted or removed, or their ranking changed.
|
||||||
|
|
||||||
|
Note: This plugin doesn't work for IOS or Windows Phone, feel free to create a pull request if you want to add that functionality to this project.
|
||||||
|
|
||||||
|
## How to install
|
||||||
|
|
||||||
|
cordova plugin add https://github.com/coconauts/NotificationListener-cordova
|
||||||
|
|
||||||
|
## Enable notification listener service
|
||||||
|
|
||||||
|
This service requires an special permission that must be enabled from settings on Android (Settings > Notifications > Notification access)
|
||||||
|
|
||||||
|
![](/settings.jpg)
|
||||||
|
|
||||||
|
Note: The app requires the following permission in your Manifest file on Android, which will be added automatically:
|
||||||
|
|
||||||
|
android.permission.BIND_NOTIFICATION_LISTENER_SERVICE
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
On Cordova initialization, add the callback for your notification-listener.
|
||||||
|
Then everytime you get a notification in your phone that callback in JS will be triggered with the notification data.
|
||||||
|
|
||||||
|
```
|
||||||
|
var app = {
|
||||||
|
initialize: function() {
|
||||||
|
console.log("Initializing app");
|
||||||
|
this.bindEvents();
|
||||||
|
},
|
||||||
|
bindEvents: function() {
|
||||||
|
console.log("Binding events");
|
||||||
|
document.addEventListener('deviceready', this.onDeviceReady, false);
|
||||||
|
},
|
||||||
|
onDeviceReady: function() {
|
||||||
|
console.log("Device ready");
|
||||||
|
|
||||||
|
notificationListener.listen(function(n){
|
||||||
|
console.log("Received notification " + JSON.stringify(n) );
|
||||||
|
}, function(e){
|
||||||
|
console.log("Notification Error " + e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
app.initialize();
|
||||||
|
```
|
||||||
|
|
||||||
|
For a full example, please see our [WatchDuino2 repository](https://github.com/coconauts/watchduino2-companion-app)
|
||||||
|
|
||||||
|
## Sample output
|
||||||
|
```
|
||||||
|
Received notification
|
||||||
|
{
|
||||||
|
"title":"Chuck Norris",
|
||||||
|
"package":"com.google.android.talk",
|
||||||
|
"text":"Hello world",
|
||||||
|
"textLines":""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notification response format
|
||||||
|
|
||||||
|
The notification response received by Javascript is a simplified object from the
|
||||||
|
[StatusBarNotification class](https://developer.android.com/reference/android/service/notification/StatusBarNotification.html)
|
||||||
|
in Android.
|
||||||
|
|
||||||
|
Feel free to update the [notification parser](#TODO) inside this plugin if needed.
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"version": "0.0.1",
|
||||||
|
"name": "net.coconauts.notification-listener",
|
||||||
|
"cordova_name": "Notification-listener",
|
||||||
|
"description": "Notification listener Plugin for Android",
|
||||||
|
"license": "Apache 2.0",
|
||||||
|
"repo": "https://github.com/coconauts/NotificationListener-cordova",
|
||||||
|
"issue": "https://github.com/coconauts/NotificationListener-cordova/issues",
|
||||||
|
"keywords": [
|
||||||
|
"notification",
|
||||||
|
"listener",
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"platforms": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": [
|
||||||
|
{
|
||||||
|
"name": "cordova",
|
||||||
|
"version": ">=3.1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<plugin
|
||||||
|
xmlns="http://www.phonegap.com/ns/plugins/1.0"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
id="net.coconauts.notification-listener"
|
||||||
|
version="0.0.1">
|
||||||
|
|
||||||
|
<name>Notification-listener</name>
|
||||||
|
<description>Notification listener Plugin for Android</description>
|
||||||
|
<license>Apache 2.0</license>
|
||||||
|
<keywords>notification, listener, android</keywords>
|
||||||
|
|
||||||
|
<repo>https://github.com/coconauts/NotificationListener-cordova</repo>
|
||||||
|
<issue>https://github.com/coconauts/NotificationListener-cordova/issues</issue>
|
||||||
|
|
||||||
|
<engines>
|
||||||
|
<engine name="cordova" version=">=3.1.0" />
|
||||||
|
</engines>
|
||||||
|
|
||||||
|
<js-module src="www/notification-listener.js" name="NotificationListener">
|
||||||
|
<clobbers target="notificationListener" />
|
||||||
|
</js-module>
|
||||||
|
|
||||||
|
<platform name="android">
|
||||||
|
<config-file target="res/xml/config.xml" parent="/*">
|
||||||
|
<feature name="NotificationListener">
|
||||||
|
<param name="android-package" value="net.coconauts.notificationListener.NotificationCommands"/>
|
||||||
|
</feature>
|
||||||
|
</config-file>
|
||||||
|
|
||||||
|
<config-file target="AndroidManifest.xml" parent="/manifest/application">
|
||||||
|
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
|
||||||
|
|
||||||
|
<service android:name="net.coconauts.notificationListener.NotificationService"
|
||||||
|
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.service.notification.NotificationListenerService" ></action>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
</config-file>
|
||||||
|
|
||||||
|
<source-file src="src/android/NotificationService.java" target-dir="src/net/coconauts/notificationListener"/>
|
||||||
|
<source-file src="src/android/NotificationCommands.java" target-dir="src/net/coconauts/notificationListener"/>
|
||||||
|
|
||||||
|
</platform>
|
||||||
|
|
||||||
|
</plugin>
|
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -0,0 +1,110 @@
|
||||||
|
package net.coconauts.notificationListener;
|
||||||
|
|
||||||
|
import android.view.Gravity;
|
||||||
|
import org.apache.cordova.CallbackContext;
|
||||||
|
import org.apache.cordova.CordovaPlugin;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import android.util.Log;
|
||||||
|
import org.apache.cordova.PluginResult;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
public class NotificationCommands extends CordovaPlugin {
|
||||||
|
|
||||||
|
private static final String TAG = "NotificationCommands";
|
||||||
|
|
||||||
|
private static final String LISTEN = "listen";
|
||||||
|
|
||||||
|
// note that webView.isPaused() is not Xwalk compatible, so tracking it poor-man style
|
||||||
|
private boolean isPaused;
|
||||||
|
|
||||||
|
private static CallbackContext listener;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
|
|
||||||
|
Log.i(TAG, "Received action " + action);
|
||||||
|
|
||||||
|
if (LISTEN.equals(action)) {
|
||||||
|
setListener(callbackContext);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
callbackContext.error(TAG+". " + action + " is not a supported function.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause(boolean multitasking) {
|
||||||
|
this.isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(boolean multitasking) {
|
||||||
|
this.isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(CallbackContext callbackContext) {
|
||||||
|
Log.i("Notification", "Attaching callback context listener " + callbackContext);
|
||||||
|
listener = callbackContext;
|
||||||
|
|
||||||
|
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||||
|
result.setKeepCallback(true);
|
||||||
|
callbackContext.sendPluginResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void notifyListener(StatusBarNotification n){
|
||||||
|
if (listener == null) {
|
||||||
|
Log.e(TAG, "Must define listener first. Call notificationListener.listen(success,error) first");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
|
JSONObject json = parse(n);
|
||||||
|
|
||||||
|
PluginResult result = new PluginResult(PluginResult.Status.OK, json);
|
||||||
|
|
||||||
|
Log.i(TAG, "Sending notification to listener " + json.toString());
|
||||||
|
result.setKeepCallback(true);
|
||||||
|
|
||||||
|
listener.sendPluginResult(result);
|
||||||
|
} catch (Exception e){
|
||||||
|
Log.e(TAG, "Unable to send notification "+ e);
|
||||||
|
listener.error(TAG+". Unable to send message: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static JSONObject parse(StatusBarNotification n) throws JSONException{
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
Bundle extras = n.getNotification().extras;
|
||||||
|
|
||||||
|
json.put("title", getExtra(extras, "android.title"));
|
||||||
|
json.put("package", n.getPackageName());
|
||||||
|
json.put("text", getExtra(extras,"android.text"));
|
||||||
|
json.put("textLines", getExtraLines(extras, "android.textLines"));
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getExtraLines(Bundle extras, String extra){
|
||||||
|
try {
|
||||||
|
CharSequence[] lines = extras.getCharSequenceArray(extra);
|
||||||
|
return lines[lines.length-1].toString();
|
||||||
|
} catch( Exception e){
|
||||||
|
Log.d(TAG, "Unable to get extra lines " + extra);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static String getExtra(Bundle extras, String extra){
|
||||||
|
try {
|
||||||
|
return extras.get(extra).toString();
|
||||||
|
} catch( Exception e){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package net.coconauts.notificationListener;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class NotificationService extends NotificationListenerService {
|
||||||
|
//http://developer.android.com/reference/android/service/notification/NotificationListenerService.html
|
||||||
|
|
||||||
|
private static final String TAG = NotificationService.class.getSimpleName();
|
||||||
|
|
||||||
|
//TODO store this in config
|
||||||
|
private static final String IGNORE_PKG = "snapdragon,com.google.android.googlequicksearchbox";
|
||||||
|
private static int notificationId = 1;
|
||||||
|
|
||||||
|
private static List<StatusBarNotification> notifications ;
|
||||||
|
public static boolean enabled = false;
|
||||||
|
private static Context context ;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
Log.i(TAG, "onCreate");
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
notifications = new ArrayList<StatusBarNotification>();
|
||||||
|
context = this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
Log.i(TAG, "onDestroy");
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onNotificationPosted(StatusBarNotification sbn) {
|
||||||
|
//Do not send notifications from this app (can cause an infinite loop)
|
||||||
|
Log.d(TAG, "notification package name " + sbn.getPackageName());
|
||||||
|
|
||||||
|
String pk = sbn.getPackageName();
|
||||||
|
|
||||||
|
if (pk.equals("android") || ignorePkg(pk) || sbn.isOngoing()) Log.d(TAG, "Ignore notification from pkg " + pk);
|
||||||
|
else {
|
||||||
|
NotificationCommands.notifyListener(sbn);
|
||||||
|
addNotification(sbn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private boolean ignorePkg(String pk){
|
||||||
|
for(String s: IGNORE_PKG.split(",")) if (pk.contains(s)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationRemoved(StatusBarNotification sbn) {
|
||||||
|
//debugNotification(sbn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNotification(StatusBarNotification msg){
|
||||||
|
notifications.add(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeAll(){
|
||||||
|
try {
|
||||||
|
for (StatusBarNotification n : notifications) remove(n);
|
||||||
|
notifications.clear();
|
||||||
|
} catch (Exception e){
|
||||||
|
Log.e(TAG, "Unable to remove notifications",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void remove(StatusBarNotification n){
|
||||||
|
String ns = Context.NOTIFICATION_SERVICE;
|
||||||
|
NotificationManager nMgr = (NotificationManager) context.getApplicationContext().getSystemService(ns);
|
||||||
|
|
||||||
|
int id = n.getId();
|
||||||
|
String tag = n.getTag();
|
||||||
|
Log.i("Cancelling notification ", tag + ", " + id);
|
||||||
|
nMgr.cancel(tag, id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
// (c) 2015 Javier Rengel (Coconauts)
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
// value must be an ArrayBuffer
|
||||||
|
listen: function (success, failure) {
|
||||||
|
console.log("Calling cordova listen method");
|
||||||
|
cordova.exec(success, failure, 'NotificationListener', 'listen', []);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue