mirror of
https://github.com/mastodon/mastodon-android.git
synced 2025-02-05 13:07:44 +01:00
Push notification improvements
This commit is contained in:
parent
c3e48d20f3
commit
0dabe89bcd
@ -79,6 +79,7 @@
|
||||
</activity>
|
||||
|
||||
<service android:name=".AudioPlayerService" android:foregroundServiceType="mediaPlayback"/>
|
||||
<service android:name=".NotificationActionHandlerService" android:exported="false"/>
|
||||
|
||||
<receiver android:name=".PushNotificationReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
|
||||
<intent-filter>
|
||||
|
@ -0,0 +1,171 @@
|
||||
package org.joinmastodon.android;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
||||
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.StatusPrivacy;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
|
||||
public class NotificationActionHandlerService extends Service{
|
||||
private static final String TAG="NotificationActionHandl";
|
||||
private int runningRequestCount=0;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId){
|
||||
String action=intent.getStringExtra("action");
|
||||
String account=intent.getStringExtra("account");
|
||||
String postID=intent.getStringExtra("post");
|
||||
String notificationTag=intent.getStringExtra("notificationTag");
|
||||
if(action==null || account==null || postID==null || notificationTag==null){
|
||||
maybeStopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
NotificationManager nm=getSystemService(NotificationManager.class);
|
||||
StatusBarNotification notification=findNotification(notificationTag);
|
||||
if("reply".equals(action)){
|
||||
CharSequence replyText=RemoteInput.getResultsFromIntent(intent).getCharSequence("replyText");
|
||||
if(replyText==null){
|
||||
maybeStopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
CreateStatus.Request req=new CreateStatus.Request();
|
||||
req.inReplyToId=postID;
|
||||
req.status=intent.getStringExtra("replyPrefix")+replyText;
|
||||
req.visibility=StatusPrivacy.valueOf(intent.getStringExtra("visibility"));
|
||||
runningRequestCount++;
|
||||
new CreateStatus(req, UUID.randomUUID().toString())
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Status result){
|
||||
E.post(new StatusCreatedEvent(result, account));
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
error.showToast(NotificationActionHandlerService.this);
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
})
|
||||
.exec(account);
|
||||
}else if("favorite".equals(action)){
|
||||
PendingIntent prevActionIntent;
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
prevActionIntent=n.actions[1].actionIntent;
|
||||
n.actions[1].actionIntent=null;
|
||||
n.actions[1].title=getString(R.string.button_favorited);
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}else{
|
||||
prevActionIntent=null;
|
||||
}
|
||||
runningRequestCount++;
|
||||
new SetStatusFavorited(postID, true)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Status result){
|
||||
E.post(new StatusCountersUpdatedEvent(result));
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
n.actions[1].actionIntent=prevActionIntent;
|
||||
n.actions[1].title=getString(R.string.button_favorite);
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}
|
||||
error.showToast(NotificationActionHandlerService.this);
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
})
|
||||
.exec(account);
|
||||
}else if("boost".equals(action)){
|
||||
PendingIntent prevActionIntent;
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
prevActionIntent=n.actions[2].actionIntent;
|
||||
n.actions[2].actionIntent=null;
|
||||
n.actions[2].title=getString(R.string.button_reblogged);
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}else{
|
||||
prevActionIntent=null;
|
||||
}
|
||||
runningRequestCount++;
|
||||
new SetStatusReblogged(postID, true)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Status result){
|
||||
E.post(new StatusCountersUpdatedEvent(result));
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
if(notification!=null){
|
||||
Notification n=notification.getNotification();
|
||||
n.actions[2].actionIntent=prevActionIntent;
|
||||
n.actions[2].title=getString(R.string.button_reblog);
|
||||
nm.notify(notificationTag, PushNotificationReceiver.NOTIFICATION_ID, n);
|
||||
}
|
||||
error.showToast(NotificationActionHandlerService.this);
|
||||
runningRequestCount--;
|
||||
maybeStopSelf();
|
||||
}
|
||||
})
|
||||
.exec(account);
|
||||
}
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
private void maybeStopSelf(){
|
||||
if(runningRequestCount==0)
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
private StatusBarNotification findNotification(String tag){
|
||||
for(StatusBarNotification sbn:getSystemService(NotificationManager.class).getActiveNotifications()){
|
||||
if(tag.equals(sbn.getTag())){
|
||||
return sbn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -5,14 +5,15 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@ -21,10 +22,13 @@ import org.joinmastodon.android.api.requests.notifications.GetNotificationByID;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Mention;
|
||||
import org.joinmastodon.android.model.PushNotification;
|
||||
import org.joinmastodon.android.model.StatusPrivacy;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@ -144,19 +148,110 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
||||
.setContentText(pn.body)
|
||||
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
|
||||
.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||
.setContentIntent(PendingIntent.getActivity(context, accountID.hashCode() & 0xFFFF, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setContentIntent(PendingIntent.getActivity(context, (accountID+pn.notificationId).hashCode() & 0xFFFF, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setWhen(notification==null ? System.currentTimeMillis() : notification.createdAt.toEpochMilli())
|
||||
.setShowWhen(true)
|
||||
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||
.setAutoCancel(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setLights(context.getColor(R.color.primary_700), 500, 1000)
|
||||
.setColor(context.getColor(R.color.primary_700));
|
||||
.setColor(context.getColor(R.color.primary_700))
|
||||
.setGroup(accountID);
|
||||
if(avatar!=null){
|
||||
builder.setLargeIcon(UiUtils.getBitmapFromDrawable(avatar));
|
||||
}
|
||||
if(AccountSessionManager.getInstance().getLoggedInAccounts().size()>1){
|
||||
builder.setSubText(accountName);
|
||||
}
|
||||
nm.notify(accountID, NOTIFICATION_ID, builder.build());
|
||||
String notificationTag=accountID+"_"+(notification==null ? 0 : notification.id);
|
||||
if(notification!=null && (notification.type==org.joinmastodon.android.model.Notification.Type.MENTION)){
|
||||
ArrayList<String> mentions=new ArrayList<>();
|
||||
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
||||
if(!notification.status.account.id.equals(ownID))
|
||||
mentions.add('@'+notification.status.account.acct);
|
||||
for(Mention mention:notification.status.mentions){
|
||||
if(mention.id.equals(ownID))
|
||||
continue;
|
||||
String m='@'+mention.acct;
|
||||
if(!mentions.contains(m))
|
||||
mentions.add(m);
|
||||
}
|
||||
String replyPrefix=mentions.isEmpty() ? "" : TextUtils.join(" ", mentions)+" ";
|
||||
|
||||
Intent replyIntent=new Intent(context, NotificationActionHandlerService.class);
|
||||
replyIntent.putExtra("action", "reply");
|
||||
replyIntent.putExtra("account", accountID);
|
||||
replyIntent.putExtra("post", notification.status.id);
|
||||
replyIntent.putExtra("notificationTag", notificationTag);
|
||||
replyIntent.putExtra("visibility", notification.status.visibility.toString());
|
||||
replyIntent.putExtra("replyPrefix", replyPrefix);
|
||||
builder.addAction(new Notification.Action.Builder(Icon.createWithResource(context, R.drawable.ic_reply_24px),
|
||||
context.getString(R.string.button_reply), PendingIntent.getService(context, (accountID+pn.notificationId+"reply").hashCode(), replyIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.addRemoteInput(new RemoteInput.Builder("replyText").build())
|
||||
.build());
|
||||
|
||||
Intent favIntent=new Intent(context, NotificationActionHandlerService.class);
|
||||
favIntent.putExtra("action", "favorite");
|
||||
favIntent.putExtra("account", accountID);
|
||||
favIntent.putExtra("post", notification.status.id);
|
||||
favIntent.putExtra("notificationTag", notificationTag);
|
||||
builder.addAction(new Notification.Action.Builder(Icon.createWithResource(context, R.drawable.ic_star_24px),
|
||||
context.getString(R.string.button_favorite), PendingIntent.getService(context, (accountID+pn.notificationId+"favorite").hashCode(), favIntent, PendingIntent.FLAG_UPDATE_CURRENT)).build());
|
||||
|
||||
PendingIntent boostActionIntent;
|
||||
if(notification.status.visibility!=StatusPrivacy.DIRECT){
|
||||
Intent boostIntent=new Intent(context, NotificationActionHandlerService.class);
|
||||
boostIntent.putExtra("action", "boost");
|
||||
boostIntent.putExtra("account", accountID);
|
||||
boostIntent.putExtra("post", notification.status.id);
|
||||
boostIntent.putExtra("notificationTag", notificationTag);
|
||||
boostActionIntent=PendingIntent.getService(context, (accountID+pn.notificationId+"boost").hashCode(), boostIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}else{
|
||||
boostActionIntent=null;
|
||||
}
|
||||
builder.addAction(new Notification.Action.Builder(Icon.createWithResource(context, R.drawable.ic_boost_24px),
|
||||
context.getString(R.string.button_reblog), boostActionIntent).build());
|
||||
}
|
||||
nm.notify(notificationTag, NOTIFICATION_ID, builder.build());
|
||||
|
||||
StatusBarNotification[] activeNotifications=nm.getActiveNotifications();
|
||||
ArrayList<String> summaryLines=new ArrayList<>();
|
||||
for(StatusBarNotification sbn:activeNotifications){
|
||||
String tag=sbn.getTag();
|
||||
if(tag!=null && tag.startsWith(accountID+"_")){
|
||||
if((sbn.getNotification().flags & Notification.FLAG_GROUP_SUMMARY)==0){
|
||||
summaryLines.add(sbn.getNotification().extras.getString("android.title"));
|
||||
if(summaryLines.size()==5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(summaryLines.size()>1){
|
||||
Notification.Builder summaryBuilder;
|
||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
|
||||
summaryBuilder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
|
||||
}else{
|
||||
summaryBuilder=new Notification.Builder(context)
|
||||
.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
}
|
||||
Notification.InboxStyle inboxStyle=new Notification.InboxStyle();
|
||||
for(String line:summaryLines){
|
||||
inboxStyle.addLine(line);
|
||||
}
|
||||
summaryBuilder.setContentTitle("content title")
|
||||
.setContentText("content text")
|
||||
.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||
.setColor(context.getColor(R.color.primary_700))
|
||||
.setContentIntent(PendingIntent.getActivity(context, accountID.hashCode() & 0xFFFF, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setWhen(notification==null ? System.currentTimeMillis() : notification.createdAt.toEpochMilli())
|
||||
.setShowWhen(true)
|
||||
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||
.setAutoCancel(true)
|
||||
.setGroup(accountID)
|
||||
.setGroupSummary(true)
|
||||
.setStyle(inboxStyle.setSummaryText(accountName));
|
||||
nm.notify(accountID+"_summary", NOTIFICATION_ID, summaryBuilder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user