Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

As in Issue #1 #3

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
/src/windows/Microsoft.Toolkit.Uwp.Notifications.*
/src/windows/**/.vs
/src/windows/**/bin
/src/windows/**/obj
/src/windows/**/obj
/.idea/
/nbproject/
*.iml
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
### Notes about this fork from
https://github.com/fquirin/cordova-plugin-local-notifications.git

- fixed the problem where the Android Notifiction Channel does not get created on first schedule
- fixed the problem where events like trigger and clear never got executed (in cordova js) when the app is not running in the backround

## Be aware
On Device Reboot all Alarms are deleted and the Restore Broadcast Receiver trys to reschedule them.
But many Manufacturers(Xiaomi, Samsung, ...) have "security" features implemented where they restrict apps from Autostart and so the BroadcastReceiver never got execute, till the user activates this autostart setting. (But they have also whitelisted very known apps like facebook, whatsapp, ...)

#### To install
Run `cordova plugin add https://github.com/mariosteinbacher/cordova-plugin-local-notifications.git --save --noregistery`

***

### Notes about this fork

- This is a merge of [@timkellypa](https://github.com/timkellypa/cordova-plugin-local-notifications), [@bhandaribhumin](https://github.com/bhandaribhumin/cordova-plugin-local-notification-12), [@powowbox](https://github.com/powowbox/cordova-plugin-local-notification-12) and my own fixes.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-local-notification",
"version": "0.10.0",
"version": "0.10.8",
"description": "Schedules and queries for local notifications",
"cordova": {
"id": "cordova-plugin-local-notification",
Expand Down Expand Up @@ -46,7 +46,7 @@
"version": ">=10.0.0"
}
],
"author": "Sebastián Katzer, fquirin, Bhumin Bhandari, powowbox and more",
"author": "Mario Steinbacher, Sebastián Katzer, fquirin, Bhumin Bhandari, powowbox and more",
"license": "Apache 2.0",
"bugs": {
"url": "https://github.com/fquirin/cordova-plugin-local-notifications/issues"
Expand Down
6 changes: 3 additions & 3 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-local-notification"
version="0.10.0">
version="0.10.8">

<name>LocalNotification</name>

<description>Schedules and queries for local notifications</description>

<repo>https://github.com/fquirin/cordova-plugin-local-notifications.git</repo>
<repo>https://github.com/mariosteinbacher/cordova-plugin-local-notifications.git</repo>

<keywords>appplant, notification, local notification, user notification</keywords>

<license>Apache 2.0</license>

<author>Sebastián Katzer, fquirin, Bhumin Bhandari, powowbox and more</author>
<author>Mario Steinbacher, Sebastián Katzer, fquirin, Bhumin Bhandari, powowbox and more</author>

<!-- cordova -->
<engines>
Expand Down
39 changes: 38 additions & 1 deletion src/android/LocalNotification.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.content.ActivityNotFoundException;
Expand All @@ -38,12 +39,15 @@
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
import android.view.View;

import android.app.NotificationManager;
import android.app.NotificationChannel;
import android.app.PendingIntent;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.content.Intent;

Expand Down Expand Up @@ -72,6 +76,7 @@
import static android.content.Context.POWER_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.S;
import static de.appplant.cordova.plugin.notification.Notification.Type.SCHEDULED;
import static de.appplant.cordova.plugin.notification.Notification.Type.TRIGGERED;

Expand Down Expand Up @@ -100,6 +105,8 @@ public class LocalNotification extends CordovaPlugin {

private static int REQUEST_IGNORE_BATTERY_CALL = 20;

private static int REQUEST_ALARM_PERMISSIONS_CALL = 30;

private CallbackContext callbackContext;

/**
Expand Down Expand Up @@ -284,6 +291,18 @@ private void requestDoNotDisturbPermissions(CallbackContext command) {
success(command, true);
}

/**
* Determine if Alarm and Reminder permissions have been granted
*
* @return true if we are granted
*/
private boolean canSetExactAlarm() {
Context context = cordova.getActivity().getApplicationContext();
AlarmManager amgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

return SDK_INT < S || amgr.canScheduleExactAlarms();
}

/**
* Determine if do not battery optimization permissions have been granted
*
Expand Down Expand Up @@ -372,6 +391,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
isIgnoringBatteryOptimizations(this.callbackContext);

this.callbackContext = null;
} else if (requestCode == REQUEST_ALARM_PERMISSIONS_CALL && this.callbackContext != null){
if(canSetExactAlarm()){
check(this.callbackContext);
} else {
success(this.callbackContext, false);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Expand Down Expand Up @@ -407,7 +432,19 @@ private void launch(CallbackContext command) {
*/
private void check(CallbackContext command) {
boolean allowed = getNotMgr().hasPermission();
success(command, allowed);
if(!canSetExactAlarm() && allowed){
JSONObject res = new JSONObject();
try {
res.put("reminder", false);
} catch (JSONException e) {
throw new RuntimeException(e);
}

PluginResult result = new PluginResult(PluginResult.Status.OK, res);
command.sendPluginResult(result);
} else {
success(command, allowed);
}
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/android/notification/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ public boolean hasPermission() {
* @param receiver Receiver to handle the trigger event.
*/
public Notification schedule(Request request, Class<?> receiver) {
Options options = request.getOptions();
Notification toast = new Notification(context, options);
// Options options = request.getOptions();
JSONObject options = request.getOptions().getDict();
Options options_with_context = new Options(context, options); //needed to create Notification Channel if not exists (AssetUtil.parse)
Notification toast = new Notification(context, options_with_context);

toast.schedule(request, receiver);

Expand Down
6 changes: 5 additions & 1 deletion src/android/notification/Notification.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ void schedule(Request request, Class<?> receiver) {
List<Pair<Date, Intent>> intents = new ArrayList<Pair<Date, Intent>>();
Set<String> ids = new ArraySet<String>();
AlarmManager mgr = getAlarmMgr();
String channelId = null;

cancelScheduledAlarms();

Expand All @@ -188,7 +189,7 @@ void schedule(Request request, Class<?> receiver) {

if (date == null)
continue;

Intent intent = new Intent(context, receiver)
.setAction(PREF_KEY_ID + request.getIdentifier())
.putExtra(Notification.EXTRA_ID, options.getId())
Expand Down Expand Up @@ -221,6 +222,9 @@ void schedule(Request request, Class<?> receiver) {
int notificationId = options.getId();
PendingIntent pi =
LaunchUtils.getBroadcastPendingIntent(context, intent, notificationId);

//check or create Notification Channel (AssetUtil.parse)
channelId = options.getChannel();

try {
switch (options.getPrio()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public void performNotification(Notification notification) {

if (autoLaunch) {
LaunchUtils.launchApp(context);
} else {
//launch App in Background to execute js/cordova code on events if app is not running
if(!checkAppRunning()) {
LaunchUtils.launchAppInBackground(context);
}
}

// Show notification if we should (triggerInApp is false)
Expand All @@ -75,10 +80,10 @@ public void performNotification(Notification notification) {
if (!options.shallWakeUp()) {
wakeUp(notification);
}

dispatchAppEvent("trigger", notification);
}

dispatchAppEvent("trigger", notification);

if (!options.isInfiniteTrigger())
return;

Expand Down
39 changes: 37 additions & 2 deletions src/android/notification/util/LaunchUtils.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package de.appplant.cordova.plugin.notification.util;

import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;

import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_FROM_BACKGROUND;



import java.util.Random;

Expand All @@ -16,7 +22,7 @@ public final class LaunchUtils {
private static int getIntentFlags() {
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (android.os.Build.VERSION.SDK_INT >= 31) {
flags |= PendingIntent.FLAG_MUTABLE;
flags |= PendingIntent.FLAG_IMMUTABLE;
}
return flags;
}
Expand Down Expand Up @@ -59,4 +65,33 @@ public static void launchApp(Context context) {

context.startActivity(intent);
}

/***
* Launch Cordova App in Background to execute JS(cordova) Code on fired Events (trigger,clear,click,...)
* @param context
*/
public static void launchAppInBackground(Context context) {
String pkgName = context.getPackageName();

Intent intent = context
.getPackageManager()
.getLaunchIntentForPackage(pkgName);

if (intent == null)
return;

//cordova start app in background if in app MainActivity implemented (moveTaskToBack)
intent.putExtra("cdvStartInBackground",true);
intent.addFlags(
FLAG_ACTIVITY_REORDER_TO_FRONT
| FLAG_ACTIVITY_SINGLE_TOP
| FLAG_FROM_BACKGROUND
| FLAG_ACTIVITY_NO_ANIMATION
| FLAG_ACTIVITY_NEW_DOCUMENT
);

ActivityOptions startoptions = ActivityOptions.makeTaskLaunchBehind();

context.startActivity(intent,startoptions.toBundle());
}
}