Skip to content

Commit 7eb413b

Browse files
notif: Introduce AndroidIntent.flags; use existing flags from zulip-mobile
1 parent ad223f9 commit 7eb413b

File tree

7 files changed

+50
-10
lines changed

7 files changed

+50
-10
lines changed

android/app/src/main/kotlin/com/zulip/flutter/Notifications.g.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ data class NotificationChannel (
9999
data class AndroidIntent (
100100
val action: String,
101101
val dataUrl: String,
102-
val extras: Map<String?, String?>
102+
val extras: Map<String?, String?>,
103+
/** A combination of flags from [IntentFlag]. */
104+
val flags: Long
103105

104106
) {
105107
companion object {
@@ -108,14 +110,16 @@ data class AndroidIntent (
108110
val action = __pigeon_list[0] as String
109111
val dataUrl = __pigeon_list[1] as String
110112
val extras = __pigeon_list[2] as Map<String?, String?>
111-
return AndroidIntent(action, dataUrl, extras)
113+
val flags = __pigeon_list[3].let { num -> if (num is Int) num.toLong() else num as Long }
114+
return AndroidIntent(action, dataUrl, extras, flags)
112115
}
113116
}
114117
fun toList(): List<Any?> {
115118
return listOf(
116119
action,
117120
dataUrl,
118121
extras,
122+
flags,
119123
)
120124
}
121125
}

android/app/src/main/kotlin/com/zulip/flutter/ZulipPlugin.kt

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ private class AndroidNotificationHost(val context: Context)
105105
MainActivity::class.java
106106
).apply {
107107
intent.extras.forEach { (k, v) -> putExtra(k!!, v!!) }
108+
flags = intent.flags.toInt()
108109
} },
109110
it.flags.toInt())
110111
) }

lib/host/android_notifications.dart

+11
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,14 @@ abstract class IntentAction {
6868
/// Corresponds to `ACTION_VIEW`.
6969
static const view = 'android.intent.action.VIEW';
7070
}
71+
72+
/// For use in [AndroidIntent.flags].
73+
///
74+
/// See: https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_BROUGHT_TO_FRONT
75+
abstract class IntentFlag {
76+
/// Corresponds to `FLAG_ACTIVITY_CLEAR_TOP`.
77+
static const activityClearTop = 1 << 26;
78+
79+
/// Corresponds to `FLAG_ACTIVITY_NEW_TASK`.
80+
static const activityNewTask = 1 << 28;
81+
}

lib/host/android_notifications.g.dart

+6
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class AndroidIntent {
7373
required this.action,
7474
required this.dataUrl,
7575
required this.extras,
76+
this.flags = 0,
7677
});
7778

7879
String action;
@@ -81,11 +82,15 @@ class AndroidIntent {
8182

8283
Map<String?, String?> extras;
8384

85+
/// A combination of flags from [IntentFlag].
86+
int flags;
87+
8488
Object encode() {
8589
return <Object?>[
8690
action,
8791
dataUrl,
8892
extras,
93+
flags,
8994
];
9095
}
9196

@@ -95,6 +100,7 @@ class AndroidIntent {
95100
action: result[0]! as String,
96101
dataUrl: result[1]! as String,
97102
extras: (result[2] as Map<Object?, Object?>?)!.cast<String?, String?>(),
103+
flags: result[3]! as int,
98104
);
99105
}
100106
}

lib/notifications/display.dart

+16-4
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,22 @@ class NotificationDisplayManager {
196196
intent: AndroidIntent(
197197
action: IntentAction.view,
198198
dataUrl: intentDataUrl.toString(),
199-
extras: {}),
200-
// TODO this doesn't set the Intent flags we set in zulip-mobile; is that OK?
201-
// (This is a legacy of `flutter_local_notifications`.)
202-
),
199+
extras: {},
200+
// See these sections in the Android docs:
201+
// https://developer.android.com/guide/components/activities/tasks-and-back-stack#TaskLaunchModes
202+
// https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_CLEAR_TOP
203+
//
204+
// * From the doc on `PendingIntent.getActivity` at
205+
// https://developer.android.com/reference/android/app/PendingIntent#getActivity(android.content.Context,%20int,%20android.content.Intent,%20int)
206+
// > Note that the activity will be started outside of the context of an
207+
// > existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK
208+
// > launch flag in the Intent.
209+
//
210+
// * The flag FLAG_ACTIVITY_CLEAR_TOP is mentioned as being what the
211+
// notification manager does; so use that. It has no effect as long
212+
// as we only have one activity; but if we add more, it will destroy
213+
// all the activities on top of the target one.
214+
flags: IntentFlag.activityClearTop | IntentFlag.activityNewTask)),
203215
autoCancel: true,
204216
);
205217

pigeon/notifications.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ class NotificationChannel {
4242
/// https://developer.android.com/reference/android/content/Intent
4343
/// https://developer.android.com/reference/android/content/Intent#Intent(java.lang.String,%20android.net.Uri,%20android.content.Context,%20java.lang.Class%3C?%3E)
4444
class AndroidIntent {
45-
AndroidIntent({required this.action, required this.dataUrl, required this.extras});
45+
AndroidIntent({required this.action, required this.dataUrl, required this.extras, this.flags = 0});
4646

4747
final String action;
4848
final String dataUrl;
4949
final Map<String?, String?> extras;
50+
51+
/// A combination of flags from [IntentFlag].
52+
final int flags;
5053
}
5154

5255
/// Corresponds to `android.app.PendingIntent`.

test/notifications/display_test.dart

+6-3
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ void main() {
225225
final expectedGroupKey = '${data.realmUrl}|${data.userId}';
226226
final expectedId =
227227
NotificationDisplayManager.notificationIdAsHashOf(expectedTag);
228-
const expectedIntentFlags = PendingIntentFlag.immutable;
228+
const expectedPendingIntentFlags = PendingIntentFlag.immutable;
229+
const expectedIntentFlags = IntentFlag.activityClearTop | IntentFlag.activityNewTask;
229230
final expectedSelfUserKey = '${data.realmUrl}|${data.userId}';
230231
final expectedIntentDataUrl = NotificationOpenPayload(
231232
realmUrl: data.realmUrl,
@@ -281,11 +282,12 @@ void main() {
281282
..autoCancel.equals(true)
282283
..contentIntent.which((it) => it.isNotNull()
283284
..requestCode.equals(0)
284-
..flags.equals(expectedIntentFlags)
285+
..flags.equals(expectedPendingIntentFlags)
285286
..intent.which((it) => it
286287
..action.equals(IntentAction.view)
287288
..dataUrl.equals(expectedIntentDataUrl.toString())
288-
..extras.deepEquals({}))),
289+
..extras.deepEquals({})
290+
..flags.equals(expectedIntentFlags))),
289291
(it) => it.isA<AndroidNotificationHostApiNotifyCall>()
290292
..id.equals(NotificationDisplayManager.notificationIdAsHashOf(expectedGroupKey))
291293
..tag.equals(expectedGroupKey)
@@ -1218,6 +1220,7 @@ extension on Subject<AndroidIntent> {
12181220
Subject<String> get action => has((x) => x.action, 'action');
12191221
Subject<String> get dataUrl => has((x) => x.dataUrl, 'dataUrl');
12201222
Subject<Map<String?, String?>> get extras => has((x) => x.extras, 'extras');
1223+
Subject<int> get flags => has((x) => x.flags, 'flags');
12211224
}
12221225

12231226
extension on Subject<InboxStyle> {

0 commit comments

Comments
 (0)