react-native-notify-kit 10.2.0 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/android/src/main/AndroidManifest.xml +0 -1
- package/android/src/main/java/app/notifee/core/ForegroundService.java +3 -1
- package/android/src/main/java/app/notifee/core/NotifeeAlarmManager.java +4 -2
- package/android/src/main/java/app/notifee/core/NotificationManager.java +43 -43
- package/android/src/main/java/app/notifee/core/ReceiverService.java +18 -13
- package/android/src/main/java/app/notifee/core/database/NotifeeCoreDatabase.java +1 -4
- package/android/src/main/java/app/notifee/core/model/ChannelModel.java +8 -13
- package/android/src/main/java/app/notifee/core/model/IntervalTriggerModel.java +2 -6
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidActionModel.java +1 -2
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidModel.java +30 -33
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidPressActionModel.java +3 -9
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidStyleModel.java +6 -4
- package/android/src/main/java/app/notifee/core/model/TimestampTriggerModel.java +7 -4
- package/android/src/main/java/app/notifee/core/utility/BundleValueReader.java +65 -0
- package/android/src/main/java/app/notifee/core/utility/IntentUtils.java +0 -28
- package/android/src/main/java/app/notifee/core/utility/ObjectUtils.java +1 -1
- package/android/src/main/java/app/notifee/core/utility/ParcelableCompatReader.java +64 -0
- package/android/src/main/java/app/notifee/core/utility/PowerManagerUtils.java +79 -41
- package/android/src/main/java/app/notifee/core/utility/ResourceUtils.java +3 -0
- package/android/src/main/kotlin/io/invertase/notifee/NotifeeApiModule.kt +1 -1
- package/android/src/main/kotlin/io/invertase/notifee/NotifeeInitProvider.kt +0 -26
- package/android/src/main/kotlin/io/invertase/notifee/NotifeeReactUtils.kt +1 -2
- package/android/src/test/java/app/notifee/core/NotifeeAlarmManagerCurrentBehaviorTest.java +446 -0
- package/android/src/test/java/app/notifee/core/NotificationManagerCreateTriggerNotificationCurrentBehaviorTest.java +203 -0
- package/android/src/test/java/app/notifee/core/NotificationManagerPressActionOptOutTest.java +180 -0
- package/android/src/test/java/app/notifee/core/NotificationReceiverHandlerInitialNotificationTest.java +157 -0
- package/android/src/test/java/app/notifee/core/ReceiverServiceInitialNotificationTest.java +169 -0
- package/android/src/test/java/app/notifee/core/model/ChannelModelTest.java +116 -0
- package/android/src/test/java/app/notifee/core/model/IntervalTriggerModelTest.java +71 -0
- package/android/src/test/java/app/notifee/core/model/NotificationAndroidModelTest.java +309 -0
- package/android/src/test/java/app/notifee/core/model/NotificationAndroidStyleModelTest.java +154 -0
- package/android/src/test/java/app/notifee/core/model/TimestampTriggerModelTest.java +296 -14
- package/android/src/test/java/app/notifee/core/utility/BundleValueReaderTest.java +131 -0
- package/android/src/test/java/app/notifee/core/utility/ObjectUtilsTest.java +142 -0
- package/android/src/test/java/app/notifee/core/utility/ParcelableCompatReaderTest.java +124 -0
- package/android/src/test/java/io/invertase/notifee/HeadlessTaskReactHostTest.java +136 -0
- package/android/src/test/java/io/invertase/notifee/NotifeeEventSubscriberRoutingTest.java +262 -0
- package/android/src/test/java/io/invertase/notifee/NotifeeReactUtilsDrawerTest.java +24 -0
- package/cli/dist/lib/patchPodfile.d.ts +3 -1
- package/cli/dist/lib/patchPodfile.js +125 -33
- package/cli/dist/lib/patchPodfile.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/types/Module.d.ts +20 -6
- package/dist/types/Notification.d.ts +5 -2
- package/dist/types/Notification.js +5 -2
- package/dist/types/Notification.js.map +1 -1
- package/dist/types/NotificationAndroid.d.ts +4 -0
- package/dist/types/NotificationAndroid.js +4 -0
- package/dist/types/NotificationAndroid.js.map +1 -1
- package/dist/types/PowerManagerInfo.d.ts +9 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/ios/NotifeeCore/NotifeeCore.m +101 -114
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/types/Module.ts +20 -6
- package/src/types/Notification.ts +5 -2
- package/src/types/NotificationAndroid.ts +4 -0
- package/src/types/PowerManagerInfo.ts +9 -4
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -421,11 +421,11 @@ As bugs are fixed, this table is updated. See [CHANGELOG.md](CHANGELOG.md) for f
|
|
|
421
421
|
|
|
422
422
|
Some upstream Notifee issues are not bugs in the library itself but platform-level limitations imposed by Android's Doze mode and vendor power management — no library code can make `AlarmManager` deliver an alarm to, or a foreground service survive inside, an app the OEM has explicitly paused. For these, the fork provides **documented mitigations**: user-facing helper APIs, code-level self-healing where possible, and decision guides that steer consumers toward the Android primitive most resilient to the specific vendor policy.
|
|
423
423
|
|
|
424
|
-
| Upstream issue | Symptom | Platform root cause | Fork mitigation
|
|
425
|
-
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
426
|
-
| [invertase/notifee#410](https://github.com/invertase/notifee/issues/410) | Foreground service paused on screen lock (Samsung OneUI, ~6 seconds after screen off on battery) and killed immediately when the app is backgrounded (Xiaomi MIUI) | Vendor aggressive battery-saver and autostart policies suspend or terminate foreground services of apps not whitelisted in the OEM's protected-apps / autostart settings. Partially Doze-related on non-exempt `foregroundServiceType` values; mostly OEM-specific behavior catalogued at [dontkillmyapp.com](https://dontkillmyapp.com/). | **(1) Decision guide** — the [Timers: foreground service or `SET_ALARM_CLOCK`?](#timers-foreground-service-or-set_alarm_clock) section recommends the `SET_ALARM_CLOCK` trigger over a silent foreground service for rest, cooking, and recovery timer use cases. `setAlarmClock` is the same primitive the stock Clock app uses and is generally respected by vendor aggressive-kill policies. **(2) Foreground service use case matrix** — the [Foreground service use case guide](#foreground-service-use-case-guide) documents which `foregroundServiceType` values are Doze-CPU-exempt, which have type-specific timeouts, and the Google Play policy constraints that rule out misusing `mediaPlayback` for silent timers. **(3) `openPowerManagerSettings()` helper API** —
|
|
427
|
-
| [invertase/notifee#734](https://github.com/invertase/notifee/issues/734) | Scheduled trigger notifications silently lost across a device reboot on OEM devices (Xiaomi MIUI, OnePlus, Huawei EMUI, Oppo ColorOS, Vivo FuntouchOS) | The vendor OS suppresses the `BOOT_COMPLETED` broadcast to apps the user has not manually whitelisted, so the library's `RebootBroadcastReceiver` never runs and persisted `AlarmManager` triggers are never re-armed after reboot. | **(1) `BOOT_COUNT` cold-start self-heal (code)** — on every app init, `InitProvider` compares `Settings.Global.BOOT_COUNT` against the last-known value in `SharedPreferences` and re-arms every persisted trigger on a background thread if a boot delta is detected, even when `BOOT_COMPLETED` was never delivered. Paired with a process-wide `AtomicBoolean` race guard in `NotifeeAlarmManager.rescheduleNotifications` that prevents double-advancement when the reboot receiver and the cold-start path race. **(2) `openPowerManagerSettings()` helper API** — the same vendor-settings deep-link used by #410, pointing the user at the autostart whitelist for defense in depth.
|
|
428
|
-
| [invertase/notifee#927](https://github.com/invertase/notifee/issues/927) | Custom sound passed via `displayNotification({ android: { sound, channelId }, ios: { sound } })` is ignored for **remote push notifications** (FCM/APNs) delivered while the app is in background or killed — the system default sound plays instead. Foreground delivery and **locally-scheduled notifications** (`displayNotification`, `createTriggerNotification`) are unaffected. | When a remote push arrives while the app is killed, the JavaScript layer never runs — the system tray item is drawn by the OS (Android system + Firebase SDK; iOS + APNs) before any Notifee code executes. On Android API 26+, the `NotificationChannel` sound is set once at channel creation and is immutable thereafter — `NotificationCompat.Builder.setSound()` is silently ignored when the builder has a `channelId`. On iOS, the Notification Service Extension only rewrites incoming push content when the payload contains a `notifee_options` key (see `NotifeeCoreExtensionHelper.m:43`); a plain APNs payload is delivered unmodified. | **Documentation only — the platform contract cannot be worked around at the library layer.** Recipes by platform: **(Android)** create the `NotificationChannel` with the desired sound at first-run (the channel sound is immutable; to change it the channel must be deleted and recreated under a new `channelId`), and configure `AndroidNotification.sound` in the FCM payload server-side so the system tray honors it for background pushes. As a heavier alternative, switch the backend to an FCM data-only payload and call `displayNotification()` from a headless task — the JS-side `android.sound` is then honored, but this trades simplicity for the cost of running JS on every push. **(iOS)** either set `aps.sound` directly in the APNs payload, or install the Notification Service Extension (see `docs/react-native/ios/remote-notification-support.mdx`) and ship the sound under `notifee_options.ios.sound` in the push payload.
|
|
424
|
+
| Upstream issue | Symptom | Platform root cause | Fork mitigation |
|
|
425
|
+
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
426
|
+
| [invertase/notifee#410](https://github.com/invertase/notifee/issues/410) | Foreground service paused on screen lock (Samsung OneUI, ~6 seconds after screen off on battery) and killed immediately when the app is backgrounded (Xiaomi MIUI) | Vendor aggressive battery-saver and autostart policies suspend or terminate foreground services of apps not whitelisted in the OEM's protected-apps / autostart settings. Partially Doze-related on non-exempt `foregroundServiceType` values; mostly OEM-specific behavior catalogued at [dontkillmyapp.com](https://dontkillmyapp.com/). | **(1) Decision guide** — the [Timers: foreground service or `SET_ALARM_CLOCK`?](#timers-foreground-service-or-set_alarm_clock) section recommends the `SET_ALARM_CLOCK` trigger over a silent foreground service for rest, cooking, and recovery timer use cases. `setAlarmClock` is the same primitive the stock Clock app uses and is generally respected by vendor aggressive-kill policies. **(2) Foreground service use case matrix** — the [Foreground service use case guide](#foreground-service-use-case-guide) documents which `foregroundServiceType` values are Doze-CPU-exempt, which have type-specific timeouts, and the Google Play policy constraints that rule out misusing `mediaPlayback` for silent timers. **(3) `openPowerManagerSettings()` helper API** — points users toward known vendor autostart / protected-apps screen candidates when available; these links are best-effort because firmware variants may move, block, or remove those settings activities. |
|
|
427
|
+
| [invertase/notifee#734](https://github.com/invertase/notifee/issues/734) | Scheduled trigger notifications silently lost across a device reboot on OEM devices (Xiaomi MIUI, OnePlus, Huawei EMUI, Oppo ColorOS, Vivo FuntouchOS) | The vendor OS suppresses the `BOOT_COMPLETED` broadcast to apps the user has not manually whitelisted, so the library's `RebootBroadcastReceiver` never runs and persisted `AlarmManager` triggers are never re-armed after reboot. | **(1) `BOOT_COUNT` cold-start self-heal (code)** — on every app init, `InitProvider` compares `Settings.Global.BOOT_COUNT` against the last-known value in `SharedPreferences` and re-arms every persisted trigger on a background thread if a boot delta is detected, even when `BOOT_COMPLETED` was never delivered. Paired with a process-wide `AtomicBoolean` race guard in `NotifeeAlarmManager.rescheduleNotifications` that prevents double-advancement when the reboot receiver and the cold-start path race. **(2) `openPowerManagerSettings()` helper API** — the same vendor-settings deep-link used by #410, pointing the user at the autostart whitelist for defense in depth. |
|
|
428
|
+
| [invertase/notifee#927](https://github.com/invertase/notifee/issues/927) | Custom sound passed via `displayNotification({ android: { sound, channelId }, ios: { sound } })` is ignored for **remote push notifications** (FCM/APNs) delivered while the app is in background or killed — the system default sound plays instead. Foreground delivery and **locally-scheduled notifications** (`displayNotification`, `createTriggerNotification`) are unaffected. | When a remote push arrives while the app is killed, the JavaScript layer never runs — the system tray item is drawn by the OS (Android system + Firebase SDK; iOS + APNs) before any Notifee code executes. On Android API 26+, the `NotificationChannel` sound is set once at channel creation and is immutable thereafter — `NotificationCompat.Builder.setSound()` is silently ignored when the builder has a `channelId`. On iOS, the Notification Service Extension only rewrites incoming push content when the payload contains a `notifee_options` key (see `NotifeeCoreExtensionHelper.m:43`); a plain APNs payload is delivered unmodified. | **Documentation only — the platform contract cannot be worked around at the library layer.** Recipes by platform: **(Android)** create the `NotificationChannel` with the desired sound at first-run (the channel sound is immutable; to change it the channel must be deleted and recreated under a new `channelId`), and configure `AndroidNotification.sound` in the FCM payload server-side so the system tray honors it for background pushes. As a heavier alternative, switch the backend to an FCM data-only payload and call `displayNotification()` from a headless task — the JS-side `android.sound` is then honored, but this trades simplicity for the cost of running JS on every push. **(iOS)** either set `aps.sound` directly in the APNs payload, or install the Notification Service Extension (see `docs/react-native/ios/remote-notification-support.mdx`) and ship the sound under `notifee_options.ios.sound` in the push payload. |
|
|
429
429
|
|
|
430
430
|
Both mitigations are intentionally additive to the existing reboot-recovery and foreground-service code paths and do not replace the consumer's responsibility to prompt the user for battery-optimization exemption when the use case warrants it. For a complete vendor-by-vendor reference of autostart, battery-saver, and background-restriction behavior, see [dontkillmyapp.com](https://dontkillmyapp.com/).
|
|
431
431
|
|
|
@@ -526,7 +526,7 @@ The fork mitigates this with two layers that work together:
|
|
|
526
526
|
|
|
527
527
|
**1. Automatic cold-start recovery.** On every app init, the library compares `Settings.Global.BOOT_COUNT` against the value recorded on the previous run. If a reboot has occurred since the last run — whether or not `BOOT_COMPLETED` was delivered to your app — the library re-arms every persisted trigger on a background thread. This means that on an OEM device where `BOOT_COMPLETED` was suppressed, simply opening your app (or having it cold-started by any other entry point: push notification, geofence, share intent) recovers all missed and upcoming alarms. Previously, opening the app alone did not recover them. This recovery runs unconditionally — it is not gated by the `notifee_init_warmup_enabled` metadata flag, because it is a correctness fix rather than a startup optimization.
|
|
528
528
|
|
|
529
|
-
**2. Vendor settings helper APIs.** The existing `getPowerManagerInfo()` and `openPowerManagerSettings()` APIs let your app guide the user
|
|
529
|
+
**2. Vendor settings helper APIs.** The existing `getPowerManagerInfo()` and `openPowerManagerSettings()` APIs let your app guide the user toward known vendor settings candidates (Xiaomi Autostart, Huawei Protected Apps, Oppo Startup Manager, and 13 more vendors) to whitelist the app. These candidates are opened best-effort: Android may reject or fail to resolve a vendor-specific settings activity on some firmware variants, and the helper fails safely instead of crashing. Consumer apps do not need to inherit package-visibility `<queries>` declarations for these helpers, and the helper does not use the direct `ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` request path. Whitelisting the app in vendor settings can restore normal reboot delivery and reduce background foreground-service kills on affected devices, but this remains subject to OEM firmware and user/device policy — so this helper is a mitigation path for **both** trigger-notification reliability and foreground-service reliability on OEM devices.
|
|
530
530
|
|
|
531
531
|
A typical integration that combines both layers looks like this:
|
|
532
532
|
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
9
9
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
10
10
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
|
11
|
-
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" android:maxSdkVersion="30" />
|
|
12
11
|
<!-- For Xiaomi devices to enable heads-up notifications as default (https://github.com/invertase/notifee/issues/296) -->
|
|
13
12
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" android:minSdkVersion="23" />
|
|
14
13
|
|
|
@@ -39,6 +39,7 @@ import app.notifee.core.event.ForegroundServiceEvent;
|
|
|
39
39
|
import app.notifee.core.event.NotificationEvent;
|
|
40
40
|
import app.notifee.core.interfaces.MethodCallResult;
|
|
41
41
|
import app.notifee.core.model.NotificationModel;
|
|
42
|
+
import app.notifee.core.utility.ParcelableCompatReader;
|
|
42
43
|
|
|
43
44
|
public class ForegroundService extends Service {
|
|
44
45
|
private static final String TAG = "ForegroundService";
|
|
@@ -186,7 +187,8 @@ public class ForegroundService extends Service {
|
|
|
186
187
|
if (extras != null) {
|
|
187
188
|
// Hash code is sent to service to ensure it is kept the same
|
|
188
189
|
int hashCode = extras.getInt("hashCode");
|
|
189
|
-
Notification notification =
|
|
190
|
+
Notification notification =
|
|
191
|
+
ParcelableCompatReader.getParcelable(extras, "notification", Notification.class);
|
|
190
192
|
Bundle bundle = extras.getBundle("notificationBundle");
|
|
191
193
|
|
|
192
194
|
if (notification != null && bundle != null) {
|
|
@@ -37,6 +37,7 @@ import app.notifee.core.model.NotificationAndroidModel;
|
|
|
37
37
|
import app.notifee.core.model.NotificationModel;
|
|
38
38
|
import app.notifee.core.model.TimestampTriggerModel;
|
|
39
39
|
import app.notifee.core.utility.AlarmUtils;
|
|
40
|
+
import app.notifee.core.utility.BundleValueReader;
|
|
40
41
|
import app.notifee.core.utility.ExtendedListenableFuture;
|
|
41
42
|
import app.notifee.core.utility.ObjectUtils;
|
|
42
43
|
import com.google.common.util.concurrent.FutureCallback;
|
|
@@ -195,7 +196,8 @@ class NotifeeAlarmManager {
|
|
|
195
196
|
NotificationManager.displayNotification(notificationModel, triggerBundle),
|
|
196
197
|
voidDisplayedNotification -> {
|
|
197
198
|
if (triggerBundle.containsKey("repeatFrequency")
|
|
198
|
-
&&
|
|
199
|
+
&& BundleValueReader.getIntPreserving(triggerBundle, "repeatFrequency")
|
|
200
|
+
!= -1) {
|
|
199
201
|
TimestampTriggerModel trigger =
|
|
200
202
|
TimestampTriggerModel.fromBundle(triggerBundle);
|
|
201
203
|
// scheduleTimestampTriggerNotification() calls setNextTimestamp()
|
|
@@ -424,7 +426,7 @@ class NotifeeAlarmManager {
|
|
|
424
426
|
NotificationModel notificationModel =
|
|
425
427
|
NotificationModel.fromBundle(ObjectUtils.bytesToBundle(notificationBytes));
|
|
426
428
|
|
|
427
|
-
int triggerType =
|
|
429
|
+
int triggerType = BundleValueReader.getIntPreserving(triggerBundle, "type");
|
|
428
430
|
|
|
429
431
|
switch (triggerType) {
|
|
430
432
|
case 0:
|
|
@@ -23,10 +23,12 @@ import static app.notifee.core.event.NotificationEvent.TYPE_ACTION_PRESS;
|
|
|
23
23
|
import static app.notifee.core.event.NotificationEvent.TYPE_PRESS;
|
|
24
24
|
import static java.lang.Integer.parseInt;
|
|
25
25
|
|
|
26
|
+
import android.Manifest;
|
|
26
27
|
import android.app.Notification;
|
|
27
28
|
import android.app.PendingIntent;
|
|
28
29
|
import android.content.Context;
|
|
29
30
|
import android.content.Intent;
|
|
31
|
+
import android.content.pm.PackageManager;
|
|
30
32
|
import android.graphics.Bitmap;
|
|
31
33
|
import android.net.Uri;
|
|
32
34
|
import android.os.Build;
|
|
@@ -59,6 +61,7 @@ import app.notifee.core.model.NotificationAndroidPressActionModel;
|
|
|
59
61
|
import app.notifee.core.model.NotificationAndroidStyleModel;
|
|
60
62
|
import app.notifee.core.model.NotificationModel;
|
|
61
63
|
import app.notifee.core.model.TimestampTriggerModel;
|
|
64
|
+
import app.notifee.core.utility.BundleValueReader;
|
|
62
65
|
import app.notifee.core.utility.ExtendedListenableFuture;
|
|
63
66
|
import app.notifee.core.utility.IntentUtils;
|
|
64
67
|
import app.notifee.core.utility.ObjectUtils;
|
|
@@ -166,18 +169,7 @@ class NotificationManager {
|
|
|
166
169
|
// so tapping the notification opens the app (defense-in-depth for paths that
|
|
167
170
|
// bypass the TS validator).
|
|
168
171
|
// 2. pressAction has the opt-out sentinel id: user explicitly passed
|
|
169
|
-
// pressAction: null in JS
|
|
170
|
-
// is created (non-tappable notification).
|
|
171
|
-
// 3. pressAction is a normal bundle: pass through unchanged.
|
|
172
|
-
// Resolve the effective pressAction bundle for the content intent.
|
|
173
|
-
// Three cases:
|
|
174
|
-
// 1. pressAction is null (absent from bundle, e.g. trigger rehydrated from Room DB
|
|
175
|
-
// after app kill): synthesize default { id:'default', launchActivity:'default' }
|
|
176
|
-
// so tapping the notification opens the app (defense-in-depth for paths that
|
|
177
|
-
// bypass the TS validator).
|
|
178
|
-
// 2. pressAction has the opt-out sentinel id: user explicitly passed
|
|
179
|
-
// pressAction: null in JS — pass null to createIntent so no launch intent
|
|
180
|
-
// is created (non-tappable notification).
|
|
172
|
+
// pressAction: null in JS, so no content intent is created.
|
|
181
173
|
// 3. pressAction is a normal bundle: pass through unchanged.
|
|
182
174
|
//
|
|
183
175
|
// pressActionForIntent → used for creating the launch intent (or null for opt-out)
|
|
@@ -203,23 +195,25 @@ class NotificationManager {
|
|
|
203
195
|
|
|
204
196
|
int targetSdkVersion =
|
|
205
197
|
ContextHolder.getApplicationContext().getApplicationInfo().targetSdkVersion;
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
198
|
+
if (pressActionForIntent != null) {
|
|
199
|
+
if (targetSdkVersion >= Build.VERSION_CODES.S
|
|
200
|
+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
201
|
+
builder.setContentIntent(
|
|
202
|
+
NotificationPendingIntent.createIntent(
|
|
203
|
+
notificationModel.getHashCode(),
|
|
204
|
+
pressActionForIntent,
|
|
205
|
+
TYPE_PRESS,
|
|
206
|
+
new String[] {"notification", "pressAction"},
|
|
207
|
+
notificationModel.toBundle(),
|
|
208
|
+
pressActionForExtras));
|
|
209
|
+
} else {
|
|
210
|
+
builder.setContentIntent(
|
|
211
|
+
ReceiverService.createIntent(
|
|
212
|
+
ReceiverService.PRESS_INTENT,
|
|
213
|
+
new String[] {"notification", "pressAction"},
|
|
214
|
+
notificationModel.toBundle(),
|
|
215
|
+
pressActionForIntent));
|
|
216
|
+
}
|
|
223
217
|
}
|
|
224
218
|
|
|
225
219
|
if (notificationModel.getTitle() != null) {
|
|
@@ -248,9 +242,7 @@ class NotificationManager {
|
|
|
248
242
|
|
|
249
243
|
builder.setColorized(androidModel.getColorized());
|
|
250
244
|
|
|
251
|
-
|
|
252
|
-
builder.setChronometerCountDown(androidModel.getChronometerCountDown());
|
|
253
|
-
}
|
|
245
|
+
builder.setChronometerCountDown(androidModel.getChronometerCountDown());
|
|
254
246
|
|
|
255
247
|
if (androidModel.getGroup() != null) {
|
|
256
248
|
builder.setGroup(androidModel.getGroup());
|
|
@@ -716,7 +708,18 @@ class NotificationManager {
|
|
|
716
708
|
Trace.endSection();
|
|
717
709
|
}
|
|
718
710
|
} else {
|
|
719
|
-
|
|
711
|
+
Context context = getApplicationContext();
|
|
712
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
|
713
|
+
&& context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
|
|
714
|
+
!= PackageManager.PERMISSION_GRANTED) {
|
|
715
|
+
String message =
|
|
716
|
+
"POST_NOTIFICATIONS permission is not granted. Notification was not"
|
|
717
|
+
+ " displayed.";
|
|
718
|
+
Logger.w(TAG, message);
|
|
719
|
+
return Futures.immediateFailedFuture(new SecurityException(message));
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
NotificationManagerCompat.from(context)
|
|
720
723
|
.notify(androidBundle.getTag(), hashCode, notification);
|
|
721
724
|
}
|
|
722
725
|
|
|
@@ -733,7 +736,7 @@ class NotificationManager {
|
|
|
733
736
|
|
|
734
737
|
static ListenableFuture<Void> createTriggerNotification(
|
|
735
738
|
NotificationModel notificationModel, Bundle triggerBundle) {
|
|
736
|
-
int triggerType =
|
|
739
|
+
int triggerType = BundleValueReader.getIntPreserving(triggerBundle, "type");
|
|
737
740
|
ListenableFuture<Void> scheduleFuture;
|
|
738
741
|
switch (triggerType) {
|
|
739
742
|
case 0:
|
|
@@ -873,10 +876,6 @@ class NotificationManager {
|
|
|
873
876
|
() -> {
|
|
874
877
|
List<Bundle> notifications = new ArrayList<Bundle>();
|
|
875
878
|
|
|
876
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
877
|
-
return notifications;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
879
|
android.app.NotificationManager notificationManager =
|
|
881
880
|
(android.app.NotificationManager)
|
|
882
881
|
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
|
@@ -896,19 +895,19 @@ class NotificationManager {
|
|
|
896
895
|
notificationBundle = new Bundle();
|
|
897
896
|
notificationBundle.putString("id", "" + sbNotification.getId());
|
|
898
897
|
|
|
899
|
-
Object title =
|
|
898
|
+
Object title = BundleValueReader.getValue(extras, Notification.EXTRA_TITLE);
|
|
900
899
|
|
|
901
900
|
if (title != null) {
|
|
902
901
|
notificationBundle.putString("title", title.toString());
|
|
903
902
|
}
|
|
904
903
|
|
|
905
|
-
Object text =
|
|
904
|
+
Object text = BundleValueReader.getValue(extras, Notification.EXTRA_TEXT);
|
|
906
905
|
|
|
907
906
|
if (text != null) {
|
|
908
907
|
notificationBundle.putString("body", text.toString());
|
|
909
908
|
}
|
|
910
909
|
|
|
911
|
-
Object subtitle =
|
|
910
|
+
Object subtitle = BundleValueReader.getValue(extras, Notification.EXTRA_SUB_TEXT);
|
|
912
911
|
|
|
913
912
|
if (subtitle != null) {
|
|
914
913
|
notificationBundle.putString("subtitle", subtitle.toString());
|
|
@@ -927,7 +926,8 @@ class NotificationManager {
|
|
|
927
926
|
|
|
928
927
|
displayNotificationBundle.putString("id", "" + sbNotification.getId());
|
|
929
928
|
} else {
|
|
930
|
-
displayNotificationBundle.putString(
|
|
929
|
+
displayNotificationBundle.putString(
|
|
930
|
+
"id", String.valueOf(BundleValueReader.getValue(notificationBundle, "id")));
|
|
931
931
|
}
|
|
932
932
|
|
|
933
933
|
if (triggerBundle != null) {
|
|
@@ -972,7 +972,7 @@ class NotificationManager {
|
|
|
972
972
|
if (!shouldIncludeInData(key)) {
|
|
973
973
|
continue;
|
|
974
974
|
}
|
|
975
|
-
Object value =
|
|
975
|
+
Object value = BundleValueReader.getValue(extras, key);
|
|
976
976
|
if (value != null) {
|
|
977
977
|
dataBundle.putString(key, value.toString());
|
|
978
978
|
}
|
|
@@ -21,6 +21,7 @@ import static app.notifee.core.event.NotificationEvent.TYPE_ACTION_PRESS;
|
|
|
21
21
|
import static app.notifee.core.event.NotificationEvent.TYPE_DISMISSED;
|
|
22
22
|
import static app.notifee.core.event.NotificationEvent.TYPE_PRESS;
|
|
23
23
|
|
|
24
|
+
import android.annotation.SuppressLint;
|
|
24
25
|
import android.app.PendingIntent;
|
|
25
26
|
import android.app.Service;
|
|
26
27
|
import android.content.Context;
|
|
@@ -171,10 +172,6 @@ public class ReceiverService extends Service {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
// ACTION_CLOSE_SYSTEM_DIALOGS is deprecated since API 31, but is still needed on API < 31
|
|
175
|
-
// to close the notification drawer after an action press. Already guarded with Build.VERSION
|
|
176
|
-
// check.
|
|
177
|
-
@SuppressWarnings("deprecation")
|
|
178
175
|
private void onActionPressIntent(Intent intent) {
|
|
179
176
|
Bundle notification = intent.getBundleExtra("notification");
|
|
180
177
|
Bundle pressAction = intent.getBundleExtra("pressAction");
|
|
@@ -221,16 +218,24 @@ public class ReceiverService extends Service {
|
|
|
221
218
|
mainComponent,
|
|
222
219
|
pressActionBundle.getLaunchActivityFlags());
|
|
223
220
|
|
|
224
|
-
|
|
225
|
-
|
|
221
|
+
closeSystemDialogsBestEffort();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
226
224
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
@SuppressWarnings("deprecation")
|
|
226
|
+
@SuppressLint("MissingPermission")
|
|
227
|
+
private void closeSystemDialogsBestEffort() {
|
|
228
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// BROADCAST_CLOSE_SYSTEM_DIALOGS is protected/system-only, so the library intentionally does
|
|
233
|
+
// not declare it. Keep this pre-Android 12 legacy broadcast best-effort; Android 12+ skips it.
|
|
234
|
+
try {
|
|
235
|
+
ContextHolder.getApplicationContext()
|
|
236
|
+
.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
|
237
|
+
} catch (SecurityException e) {
|
|
238
|
+
Logger.w(TAG, "Unable to close system dialogs with legacy broadcast", e);
|
|
234
239
|
}
|
|
235
240
|
}
|
|
236
241
|
|
|
@@ -43,10 +43,7 @@ public abstract class NotifeeCoreDatabase extends RoomDatabase {
|
|
|
43
43
|
static final ListeningExecutorService databaseWriteListeningExecutor =
|
|
44
44
|
MoreExecutors.listeningDecorator(databaseWriteExecutor);
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
* Migrate from: version 1 to version 2 - where the {@link WorkDataEntity} has an extra field:
|
|
48
|
-
* alert
|
|
49
|
-
*/
|
|
46
|
+
/** Migrate from version 1 to version 2 by adding the with_alarm_manager column. */
|
|
50
47
|
@VisibleForTesting
|
|
51
48
|
static final Migration MIGRATION_1_2 =
|
|
52
49
|
new Migration(1, 2) {
|
|
@@ -23,7 +23,7 @@ import androidx.annotation.NonNull;
|
|
|
23
23
|
import androidx.annotation.Nullable;
|
|
24
24
|
import androidx.core.app.NotificationCompat;
|
|
25
25
|
import androidx.core.app.NotificationManagerCompat;
|
|
26
|
-
import app.notifee.core.utility.
|
|
26
|
+
import app.notifee.core.utility.BundleValueReader;
|
|
27
27
|
import java.util.ArrayList;
|
|
28
28
|
import java.util.Objects;
|
|
29
29
|
|
|
@@ -72,11 +72,8 @@ public class ChannelModel {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
public Integer getImportance() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return NotificationManagerCompat.IMPORTANCE_DEFAULT;
|
|
75
|
+
return BundleValueReader.getIntPreserving(
|
|
76
|
+
mChannelBundle, "importance", NotificationManagerCompat.IMPORTANCE_DEFAULT);
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
public @Nullable Integer getLightColor() {
|
|
@@ -88,14 +85,11 @@ public class ChannelModel {
|
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
public int getVisibility() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return NotificationCompat.VISIBILITY_PRIVATE;
|
|
88
|
+
return BundleValueReader.getIntPreserving(
|
|
89
|
+
mChannelBundle, "visibility", NotificationCompat.VISIBILITY_PRIVATE);
|
|
96
90
|
}
|
|
97
91
|
|
|
98
|
-
//
|
|
92
|
+
// BundleValueReader.getArrayListValue returns ArrayList<?>, so the (Integer) cast is inherently
|
|
99
93
|
// unchecked but correct for our serialization format.
|
|
100
94
|
@SuppressWarnings("unchecked")
|
|
101
95
|
public long[] getVibrationPattern() {
|
|
@@ -104,7 +98,8 @@ public class ChannelModel {
|
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
ArrayList<?> vibrationPattern =
|
|
107
|
-
Objects.requireNonNull(
|
|
101
|
+
Objects.requireNonNull(
|
|
102
|
+
BundleValueReader.getArrayListValue(mChannelBundle, "vibrationPattern"));
|
|
108
103
|
|
|
109
104
|
long[] vibrateArray = new long[vibrationPattern.size()];
|
|
110
105
|
|
|
@@ -20,7 +20,7 @@ package app.notifee.core.model;
|
|
|
20
20
|
import android.os.Bundle;
|
|
21
21
|
import androidx.annotation.NonNull;
|
|
22
22
|
import app.notifee.core.Logger;
|
|
23
|
-
import app.notifee.core.utility.
|
|
23
|
+
import app.notifee.core.utility.BundleValueReader;
|
|
24
24
|
import java.util.concurrent.TimeUnit;
|
|
25
25
|
|
|
26
26
|
public class IntervalTriggerModel {
|
|
@@ -54,10 +54,6 @@ public class IntervalTriggerModel {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
public int getInterval() {
|
|
57
|
-
|
|
58
|
-
return ObjectUtils.getInt(mIntervalTriggerBundle.get("interval"));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return -1;
|
|
57
|
+
return BundleValueReader.getIntPreserving(mIntervalTriggerBundle, "interval", -1);
|
|
62
58
|
}
|
|
63
59
|
}
|
|
@@ -77,8 +77,7 @@ public class NotificationAndroidActionModel {
|
|
|
77
77
|
* @return RemoteInput
|
|
78
78
|
*/
|
|
79
79
|
public @Nullable RemoteInput getRemoteInput(NotificationCompat.Action.Builder actionBuilder) {
|
|
80
|
-
if (mNotificationAndroidActionBundle.containsKey("input")
|
|
81
|
-
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH) {
|
|
80
|
+
if (mNotificationAndroidActionBundle.containsKey("input")) {
|
|
82
81
|
Bundle inputBundle =
|
|
83
82
|
Objects.requireNonNull(mNotificationAndroidActionBundle.getBundle("input"));
|
|
84
83
|
|
|
@@ -29,7 +29,9 @@ import androidx.annotation.RequiresApi;
|
|
|
29
29
|
import androidx.core.app.NotificationCompat;
|
|
30
30
|
import androidx.core.app.NotificationManagerCompat;
|
|
31
31
|
import app.notifee.core.Logger;
|
|
32
|
+
import app.notifee.core.utility.BundleValueReader;
|
|
32
33
|
import app.notifee.core.utility.ObjectUtils;
|
|
34
|
+
import app.notifee.core.utility.ParcelableCompatReader;
|
|
33
35
|
import app.notifee.core.utility.ResourceUtils;
|
|
34
36
|
import java.util.ArrayList;
|
|
35
37
|
import java.util.Objects;
|
|
@@ -50,7 +52,9 @@ public class NotificationAndroidModel {
|
|
|
50
52
|
public @Nullable ArrayList<NotificationAndroidActionModel> getActions() {
|
|
51
53
|
if (mNotificationAndroidBundle.containsKey("actions")) {
|
|
52
54
|
ArrayList<Bundle> actionBundles =
|
|
53
|
-
Objects.requireNonNull(
|
|
55
|
+
Objects.requireNonNull(
|
|
56
|
+
ParcelableCompatReader.getParcelableArrayList(
|
|
57
|
+
mNotificationAndroidBundle, "actions", Bundle.class));
|
|
54
58
|
ArrayList<NotificationAndroidActionModel> actions = new ArrayList<>(actionBundles.size());
|
|
55
59
|
|
|
56
60
|
for (Bundle actionBundle : actionBundles) {
|
|
@@ -72,7 +76,8 @@ public class NotificationAndroidModel {
|
|
|
72
76
|
|
|
73
77
|
ArrayList<?> foregroundServiceTypesArrayList =
|
|
74
78
|
Objects.requireNonNull(
|
|
75
|
-
|
|
79
|
+
BundleValueReader.getArrayListValue(
|
|
80
|
+
mNotificationAndroidBundle, "foregroundServiceTypes"));
|
|
76
81
|
|
|
77
82
|
if (foregroundServiceTypesArrayList.isEmpty()) {
|
|
78
83
|
Logger.w(TAG, "foregroundServiceTypes is empty; treating as absent");
|
|
@@ -137,12 +142,8 @@ public class NotificationAndroidModel {
|
|
|
137
142
|
* @return Integer
|
|
138
143
|
*/
|
|
139
144
|
public @Nullable Integer getBadgeIconType() {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return ObjectUtils.getInt(mNotificationAndroidBundle.get("badgeIconType"));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return NotificationCompat.BADGE_ICON_LARGE;
|
|
145
|
+
return BundleValueReader.getIntPreserving(
|
|
146
|
+
mNotificationAndroidBundle, "badgeIconType", NotificationCompat.BADGE_ICON_LARGE);
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
/**
|
|
@@ -266,11 +267,8 @@ public class NotificationAndroidModel {
|
|
|
266
267
|
* @return int
|
|
267
268
|
*/
|
|
268
269
|
public int getGroupAlertBehaviour() {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return NotificationCompat.GROUP_ALERT_ALL;
|
|
270
|
+
return BundleValueReader.getIntPreserving(
|
|
271
|
+
mNotificationAndroidBundle, "groupAlertBehavior", NotificationCompat.GROUP_ALERT_ALL);
|
|
274
272
|
}
|
|
275
273
|
|
|
276
274
|
/**
|
|
@@ -327,14 +325,15 @@ public class NotificationAndroidModel {
|
|
|
327
325
|
*
|
|
328
326
|
* @return ArrayList<Integer>
|
|
329
327
|
*/
|
|
330
|
-
//
|
|
328
|
+
// BundleValueReader.getArrayListValue returns ArrayList<?>, so element casts to String/Integer
|
|
331
329
|
// are inherently unchecked but correct for our serialization format.
|
|
332
330
|
@SuppressWarnings("unchecked")
|
|
333
331
|
public @Nullable ArrayList<Integer> getLights() {
|
|
334
332
|
if (mNotificationAndroidBundle.containsKey("lights")) {
|
|
335
333
|
try {
|
|
336
334
|
ArrayList<?> lightList =
|
|
337
|
-
Objects.requireNonNull(
|
|
335
|
+
Objects.requireNonNull(
|
|
336
|
+
BundleValueReader.getArrayListValue(mNotificationAndroidBundle, "lights"));
|
|
338
337
|
String rawColor = (String) lightList.get(0);
|
|
339
338
|
|
|
340
339
|
ArrayList<Integer> lights = new ArrayList<>(3);
|
|
@@ -368,7 +367,7 @@ public class NotificationAndroidModel {
|
|
|
368
367
|
*/
|
|
369
368
|
public Integer getNumber() {
|
|
370
369
|
if (mNotificationAndroidBundle.containsKey("badgeCount")) {
|
|
371
|
-
return
|
|
370
|
+
return BundleValueReader.getIntPreserving(mNotificationAndroidBundle, "badgeCount");
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
return null;
|
|
@@ -403,7 +402,8 @@ public class NotificationAndroidModel {
|
|
|
403
402
|
}
|
|
404
403
|
|
|
405
404
|
ArrayList<?> flagsArrayList =
|
|
406
|
-
Objects.requireNonNull(
|
|
405
|
+
Objects.requireNonNull(
|
|
406
|
+
BundleValueReader.getArrayListValue(mNotificationAndroidBundle, "flags"));
|
|
407
407
|
|
|
408
408
|
int[] flagsArray = new int[flagsArrayList.size()];
|
|
409
409
|
|
|
@@ -469,7 +469,11 @@ public class NotificationAndroidModel {
|
|
|
469
469
|
return NotificationCompat.PRIORITY_DEFAULT;
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
-
int importance =
|
|
472
|
+
int importance =
|
|
473
|
+
BundleValueReader.getIntPreserving(
|
|
474
|
+
mNotificationAndroidBundle,
|
|
475
|
+
"importance",
|
|
476
|
+
NotificationManagerCompat.IMPORTANCE_DEFAULT);
|
|
473
477
|
switch (importance) {
|
|
474
478
|
case NotificationManagerCompat.IMPORTANCE_HIGH:
|
|
475
479
|
return NotificationCompat.PRIORITY_HIGH;
|
|
@@ -494,8 +498,8 @@ public class NotificationAndroidModel {
|
|
|
494
498
|
Objects.requireNonNull(mNotificationAndroidBundle.getBundle("progress"));
|
|
495
499
|
|
|
496
500
|
return new AndroidProgress(
|
|
497
|
-
|
|
498
|
-
|
|
501
|
+
BundleValueReader.getIntPreserving(progressBundle, "max"),
|
|
502
|
+
BundleValueReader.getIntPreserving(progressBundle, "current"),
|
|
499
503
|
progressBundle.getBoolean("indeterminate", false));
|
|
500
504
|
}
|
|
501
505
|
|
|
@@ -607,7 +611,7 @@ public class NotificationAndroidModel {
|
|
|
607
611
|
*/
|
|
608
612
|
public @Nullable Long getTimeoutAfter() {
|
|
609
613
|
if (mNotificationAndroidBundle.containsKey("timeoutAfter")) {
|
|
610
|
-
return
|
|
614
|
+
return BundleValueReader.getLongPreserving(mNotificationAndroidBundle, "timeoutAfter");
|
|
611
615
|
}
|
|
612
616
|
|
|
613
617
|
return null;
|
|
@@ -635,7 +639,7 @@ public class NotificationAndroidModel {
|
|
|
635
639
|
*
|
|
636
640
|
* @return long[]
|
|
637
641
|
*/
|
|
638
|
-
//
|
|
642
|
+
// BundleValueReader.getArrayListValue returns ArrayList<?>, so the (Integer) cast is inherently
|
|
639
643
|
// unchecked but correct for our serialization format.
|
|
640
644
|
@SuppressWarnings("unchecked")
|
|
641
645
|
public long[] getVibrationPattern() {
|
|
@@ -645,7 +649,7 @@ public class NotificationAndroidModel {
|
|
|
645
649
|
|
|
646
650
|
ArrayList<?> vibrationPattern =
|
|
647
651
|
Objects.requireNonNull(
|
|
648
|
-
|
|
652
|
+
BundleValueReader.getArrayListValue(mNotificationAndroidBundle, "vibrationPattern"));
|
|
649
653
|
|
|
650
654
|
long[] vibrateArray = new long[vibrationPattern.size()];
|
|
651
655
|
|
|
@@ -663,11 +667,8 @@ public class NotificationAndroidModel {
|
|
|
663
667
|
* @return int
|
|
664
668
|
*/
|
|
665
669
|
public int getVisibility() {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
return NotificationCompat.VISIBILITY_PRIVATE;
|
|
670
|
+
return BundleValueReader.getIntPreserving(
|
|
671
|
+
mNotificationAndroidBundle, "visibility", NotificationCompat.VISIBILITY_PRIVATE);
|
|
671
672
|
}
|
|
672
673
|
|
|
673
674
|
/**
|
|
@@ -676,11 +677,7 @@ public class NotificationAndroidModel {
|
|
|
676
677
|
* @return long
|
|
677
678
|
*/
|
|
678
679
|
public long getTimestamp() {
|
|
679
|
-
|
|
680
|
-
return ObjectUtils.getLong(mNotificationAndroidBundle.get("timestamp"));
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
return -1;
|
|
680
|
+
return BundleValueReader.getLongPreserving(mNotificationAndroidBundle, "timestamp", -1L);
|
|
684
681
|
}
|
|
685
682
|
|
|
686
683
|
public static class AndroidProgress {
|