File indexing completed on 2024-12-22 04:41:40

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 package org.kde.kdeconnect.Plugins.ReceiveNotificationsPlugin;
0008 
0009 import android.Manifest;
0010 import android.app.Notification;
0011 import android.app.NotificationManager;
0012 import android.app.PendingIntent;
0013 import android.content.Intent;
0014 import android.graphics.Bitmap;
0015 import android.graphics.BitmapFactory;
0016 import android.os.Build;
0017 import android.util.Log;
0018 
0019 import androidx.annotation.NonNull;
0020 import androidx.core.app.NotificationCompat;
0021 import androidx.core.content.ContextCompat;
0022 
0023 import org.apache.commons.lang3.ArrayUtils;
0024 import org.kde.kdeconnect.Helpers.NotificationHelper;
0025 import org.kde.kdeconnect.NetworkPacket;
0026 import org.kde.kdeconnect.Plugins.Plugin;
0027 import org.kde.kdeconnect.Plugins.PluginFactory;
0028 import org.kde.kdeconnect.UserInterface.MainActivity;
0029 import org.kde.kdeconnect_tp.R;
0030 
0031 import java.io.InputStream;
0032 
0033 @PluginFactory.LoadablePlugin
0034 public class ReceiveNotificationsPlugin extends Plugin {
0035 
0036     private final static String PACKET_TYPE_NOTIFICATION = "kdeconnect.notification";
0037     private final static String PACKET_TYPE_NOTIFICATION_REQUEST = "kdeconnect.notification.request";
0038 
0039     @Override
0040     public @NonNull String getDisplayName() {
0041         return context.getResources().getString(R.string.pref_plugin_receive_notifications);
0042     }
0043 
0044     @Override
0045     public @NonNull String getDescription() {
0046         return context.getResources().getString(R.string.pref_plugin_receive_notifications_desc);
0047     }
0048 
0049     @Override
0050     public boolean isEnabledByDefault() {
0051         return false;
0052     }
0053 
0054     @Override
0055     public boolean onCreate() {
0056         // request all existing notifications
0057         NetworkPacket np = new NetworkPacket(PACKET_TYPE_NOTIFICATION_REQUEST);
0058         np.set("request", true);
0059         device.sendPacket(np);
0060         return true;
0061     }
0062 
0063     @Override
0064     public boolean onPacketReceived(final NetworkPacket np) {
0065 
0066         if (!np.has("ticker") || !np.has("appName") || !np.has("id")) {
0067             Log.e("NotificationsPlugin", "Received notification packet lacks properties");
0068             return true;
0069         }
0070 
0071         if (np.getBoolean("silent", false)) {
0072             return true;
0073         }
0074 
0075         PendingIntent resultPendingIntent = PendingIntent.getActivity(
0076                 context,
0077                 0,
0078                 new Intent(context, MainActivity.class),
0079                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE
0080         );
0081 
0082         Bitmap largeIcon = null;
0083         if (np.hasPayload()) {
0084             int width = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
0085             int height = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
0086             final InputStream input = np.getPayload().getInputStream();
0087             largeIcon = BitmapFactory.decodeStream(input);
0088             np.getPayload().close();
0089 
0090             if (largeIcon != null) {
0091                 //Log.i("NotificationsPlugin", "hasPayload: size=" + largeIcon.getWidth() + "/" + largeIcon.getHeight() + " opti=" + width + "/" + height);
0092                 if (largeIcon.getWidth() > width || largeIcon.getHeight() > height) {
0093                     // older API levels don't scale notification icons automatically, therefore:
0094                     largeIcon = Bitmap.createScaledBitmap(largeIcon, width, height, false);
0095                 }
0096             }
0097         }
0098 
0099         NotificationManager notificationManager = ContextCompat.getSystemService(context, NotificationManager.class);
0100 
0101         Notification noti = new NotificationCompat.Builder(context, NotificationHelper.Channels.RECEIVENOTIFICATION)
0102                 .setContentTitle(np.getString("appName"))
0103                 .setContentText(np.getString("ticker"))
0104                 .setContentIntent(resultPendingIntent)
0105                 .setTicker(np.getString("ticker"))
0106                 .setSmallIcon(R.drawable.ic_notification)
0107                 .setLargeIcon(largeIcon)
0108                 .setAutoCancel(true)
0109                 .setLocalOnly(true)  // to avoid bouncing the notification back to other kdeconnect nodes
0110                 .setDefaults(Notification.DEFAULT_ALL)
0111                 .setStyle(new NotificationCompat.BigTextStyle().bigText(np.getString("ticker")))
0112                 .build();
0113 
0114         NotificationHelper.notifyCompat(notificationManager, "kdeconnectId:" + np.getString("id", "0"), np.getInt("id", 0), noti);
0115 
0116         return true;
0117     }
0118 
0119     @Override
0120     public @NonNull String[] getSupportedPacketTypes() {
0121         return new String[]{PACKET_TYPE_NOTIFICATION};
0122     }
0123 
0124     @Override
0125     public @NonNull String[] getOutgoingPacketTypes() {
0126         return new String[]{PACKET_TYPE_NOTIFICATION_REQUEST};
0127     }
0128 
0129     @NonNull
0130     @Override
0131     protected String[] getRequiredPermissions() {
0132         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
0133             return new String[]{Manifest.permission.POST_NOTIFICATIONS};
0134         } else {
0135             return ArrayUtils.EMPTY_STRING_ARRAY;
0136         }
0137     }
0138 
0139     @Override
0140     protected int getPermissionExplanation() {
0141         return R.string.receive_notifications_permission_explanation;
0142     }
0143 }