First commit
This commit is contained in:
commit
29f9e8ddab
3
CHANGES.txt
Normal file
3
CHANGES.txt
Normal file
@ -0,0 +1,3 @@
|
||||
= 0.0.1 =
|
||||
|
||||
In progress
|
13
LICENSE.txt
Normal file
13
LICENSE.txt
Normal file
@ -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.
|
72
README.md
Normal file
72
README.md
Normal file
@ -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.
|
23
package.json
Normal file
23
package.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
48
plugin.xml
Normal file
48
plugin.xml
Normal file
@ -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>
|
BIN
settings.jpg
Normal file
BIN
settings.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
110
src/android/NotificationCommands.java
Normal file
110
src/android/NotificationCommands.java
Normal file
@ -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 "";
|
||||
}
|
||||
}
|
||||
}
|
88
src/android/NotificationService.java
Normal file
88
src/android/NotificationService.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
24
www/notification-listener.js
Normal file
24
www/notification-listener.js
Normal file
@ -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
Block a user