Resolves #471 Actionable notification
This commit is contained in:
parent
92a1230267
commit
55868d1dfe
@ -56,6 +56,12 @@
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<receiver android:name=".NotificationActionReceiver" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
|
||||
|
@ -1,6 +1,10 @@
|
||||
package com.keyboardcrumbs.hassclient;
|
||||
|
||||
import java.util.Map;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@ -16,8 +20,9 @@ import android.util.Log;
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.webkit.URLUtil;
|
||||
|
||||
|
||||
public class MessagingService extends FirebaseMessagingService {
|
||||
@ -31,14 +36,7 @@ public class MessagingService extends FirebaseMessagingService {
|
||||
if (data.size() > 0) {
|
||||
Log.d(TAG, "Message data payload: " + data);
|
||||
if (data.containsKey("body") || data.containsKey("title")) {
|
||||
sendNotification(
|
||||
data.get("body"),
|
||||
data.get("title"),
|
||||
data.get("channelId"),
|
||||
data.get("action1"),
|
||||
data.get("action2"),
|
||||
data.get("action3")
|
||||
);
|
||||
sendNotification(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,22 +47,31 @@ public class MessagingService extends FirebaseMessagingService {
|
||||
//TODO update token
|
||||
}
|
||||
|
||||
private void executeAction() {
|
||||
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(NotificationActionWorker.class)
|
||||
.build();
|
||||
WorkManager.getInstance().beginWith(work).enqueue();
|
||||
}
|
||||
|
||||
private void sendNotification(String messageBody, String messageTitle, String channelId, String action1, String action2, String action3) {
|
||||
if (channelId == null) {
|
||||
private void sendNotification(Map<String, String> data) {
|
||||
String channelId, messageBody, messageTitle, imageUrl;
|
||||
String nTag;
|
||||
if (!data.containsKey("channelId")) {
|
||||
channelId = "ha_notify";
|
||||
} else {
|
||||
channelId = data.get("channelId");
|
||||
}
|
||||
if (messageBody == null) {
|
||||
if (!data.containsKey("body")) {
|
||||
messageBody = "";
|
||||
} else {
|
||||
messageBody = data.get("body");
|
||||
}
|
||||
if (messageTitle == null) {
|
||||
if (!data.containsKey("title")) {
|
||||
messageTitle = "HA Client";
|
||||
} else {
|
||||
messageTitle = data.get("title");
|
||||
}
|
||||
if (!data.containsKey("tag")) {
|
||||
nTag = String.valueOf(System.currentTimeMillis());
|
||||
} else {
|
||||
nTag = data.get("tag");
|
||||
}
|
||||
Log.d(TAG, "Notification tag: " + nTag);
|
||||
imageUrl = data.get("image");
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
|
||||
@ -75,10 +82,26 @@ public class MessagingService extends FirebaseMessagingService {
|
||||
.setSmallIcon(R.drawable.mini_icon)
|
||||
.setContentTitle(messageTitle)
|
||||
.setContentText(messageBody)
|
||||
.setAutoCancel(false)
|
||||
.setAutoCancel(true)
|
||||
.setSound(defaultSoundUri)
|
||||
.setContentIntent(pendingIntent);
|
||||
|
||||
if (URLUtil.isValidUrl(imageUrl)) {
|
||||
Bitmap image = getBitmapFromURL(imageUrl);
|
||||
if (image != null) {
|
||||
notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(image).bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.blank_icon)));
|
||||
notificationBuilder.setLargeIcon(image);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
if (data.containsKey("action" + i)) {
|
||||
Intent broadcastIntent = new Intent(this, NotificationActionReceiver.class);
|
||||
Log.d(TAG, "Putting a tag to the action: " + nTag);
|
||||
broadcastIntent.putExtra("tag", nTag);
|
||||
broadcastIntent.putExtra("actionData", data.get("action" + i + "_data"));
|
||||
PendingIntent actionIntent = PendingIntent.getBroadcast(this, i, broadcastIntent, 0);
|
||||
notificationBuilder.addAction(R.drawable.mini_icon, data.get("action" + i), actionIntent);
|
||||
}
|
||||
}
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
@ -90,6 +113,19 @@ public class MessagingService extends FirebaseMessagingService {
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
|
||||
notificationManager.notify(nTag, 0 /* ID of notification */, notificationBuilder.build());
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromURL(String imageUrl) {
|
||||
try {
|
||||
URL url = new URL(imageUrl);
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.connect();
|
||||
InputStream input = connection.getInputStream();
|
||||
return BitmapFactory.decodeStream(input);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.keyboardcrumbs.hassclient;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
|
||||
import android.webkit.URLUtil;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class NotificationActionReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "NotificationActionReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String rawActionData = intent.getStringExtra("actionData");
|
||||
String notificationTag = intent.getStringExtra("tag");
|
||||
Log.d(TAG, "Has 'tag': " + intent.hasExtra("tag"));
|
||||
Log.d(TAG, "Canceling notification by tag: " + notificationTag);
|
||||
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(notificationTag, 0);
|
||||
SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
|
||||
String webhookId = prefs.getString("flutter.app-webhook-id", null);
|
||||
if (webhookId != null) {
|
||||
try {
|
||||
Log.d(TAG, "Got webhook id");
|
||||
String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
|
||||
"://" +
|
||||
prefs.getString("flutter.hassio-domain", "") +
|
||||
":" +
|
||||
prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
|
||||
JSONObject actionData = new JSONObject(rawActionData);
|
||||
Log.d(TAG, "request url: " + requestUrl);
|
||||
if (URLUtil.isValidUrl(requestUrl)) {
|
||||
JSONObject dataToSend = new JSONObject();
|
||||
JSONObject requestData = new JSONObject();
|
||||
if (actionData.getString("action").equals("call-service")) {
|
||||
dataToSend.put("type", "call_service");
|
||||
requestData.put("domain", actionData.getString("service").split("\\.")[0]);
|
||||
requestData.put("service", actionData.getString("service").split("\\.")[1]);
|
||||
if (actionData.has("service_data")) {
|
||||
requestData.put("service_data", actionData.get("service_data"));
|
||||
}
|
||||
} else {
|
||||
dataToSend.put("type", "fire_event");
|
||||
requestData.put("event_type", "ha_client_event");
|
||||
}
|
||||
dataToSend.put("data", requestData);
|
||||
String stringRequest = dataToSend.toString();
|
||||
Log.d(TAG, "Data to send home: " + stringRequest);
|
||||
SendTask sendTask = new SendTask();
|
||||
sendTask.execute(requestUrl, stringRequest);
|
||||
} else {
|
||||
Log.w(TAG, "Invalid url");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error handling notification action", e);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Webhook id not found");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.keyboardcrumbs.hassclient;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
public class NotificationActionWorker extends Worker {
|
||||
|
||||
private static final String TAG = "NotificationActionWorker";
|
||||
|
||||
public NotificationActionWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
|
||||
super(appContext, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Log.d(TAG, "Performing long running task in scheduled job");
|
||||
// TODO(developer): add long running task here.
|
||||
return Result.success();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.keyboardcrumbs.hassclient;
|
||||
|
||||
import android.util.Log;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SendTask extends AsyncTask<String, String, String> {
|
||||
|
||||
private static final String TAG = "SendTask";
|
||||
|
||||
public SendTask(){
|
||||
//set context variables if required
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
String urlString = params[0];
|
||||
String data = params[1];
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Connecting and sending...");
|
||||
URL url = new URL(urlString);
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setRequestProperty("Content-Type", "application/json");
|
||||
urlConnection.setDoOutput(true);
|
||||
byte[] outputBytes = data.getBytes("UTF-8");
|
||||
OutputStream os = urlConnection.getOutputStream();
|
||||
os.write(outputBytes);
|
||||
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
|
||||
Log.d(TAG, "responseCode: " + responseCode);
|
||||
urlConnection.disconnect();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error sending data", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
BIN
android/app/src/main/res/drawable/blank_icon.png
Normal file
BIN
android/app/src/main/res/drawable/blank_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 461 B |
Reference in New Issue
Block a user