I have a two-activity android app (the activities are both single-top) and I am handling push notifications. Every push notification scenario is handled perfectly for me except for one, which is because of how the push notification intents are constructed.
The scenario that does not perform as desired is when the user is in one activity when the push notification comes in, and then they navigate to a different activity, at which point they then decide to select the push notification from their phone's dropdown bar. My problem is that the app then attempts to go back to the activity that was active when the notification was created, which isn't what I want. I want it to still do everything that it would do with the notification and its data the same way, but instead do it on the current activity and not switch back.
I know why it is happening, because the notification creation code is designed like this:
// create notification
val builder = NotificationCompat.Builder(context,
channelId)
// more things are done to set up the builder...
// here is why the problem is happening
val notificationIntent = if (we_are_in_activity_one)
Intent(context, ActivityOne::class.java)
else
Intent(context, ActivityTwo::class.java)
notificationIntent.putExtras(data_from_notification)
builder.setContentIntent(PendingIntent.getActivity(context,
notificationId,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
//Auto cancel
builder.setAutoCancel(true)
builder.priority = NotificationCompat.PRIORITY_HIGH
//Return the generated notification
return builder
What I am wondering is what can be done or changed so that when the user selects the notification, it doesn't automatically start up the activity that it was originally bundled with if circumstances have changed. Is there maybe an obvious flag I am missing that I can use?
Another piece of info that may be helpful is that it is only a problem when they are in activity 2, as activity 1 is the launcher activity. So if the notification is created while in 2, but they navigate back to 1, Activity 2 won't be active anymore. When they tap the notification, it restarts activity 2, which isn't what I want. I would only want the notification to actually go back to Activity 2 if it is still active (aka the user is still on it).
Thanks in advance and let me know if I can provide any more helpful information
If I understand correctly, do you want to receive notification on the user's current activity?
You can do it as follows.
You need to verify that the second activity is running. If it is not, your notification will open on the main screen. If it is, the notification will be opened on it in onNewIntent()
.
An easy way to achieve this would be:
public static boolean isActivityActive(Activity activity) {
return !activity.isFinishing() && !activity.isDestroyed();
}
and then
Intent intent = new Intent(context, !isActivityActive(new ActivityTwo()) ? ActivityOne.class : ActivityTwo.class);
This method will return true if the activity is open. Alternatively you can use:
activity.getWindow().getDecorView().isShown();
in isActivityActive(Activity)
The value returned by this expression changes in onStart()
/ onStop()
If the method above does not provide the result you expect, you can create a class for reuse and save the activity state to shared keys that you can use in any activity.
Only a few lines of code are needed.
First do the following:
public class MyPreference {
private Context c;
private SharedPreferences.Editor editor;
private SharedPreferences preferences;
public MyPreference (Context c) {
this.c = c;
preferences = c.getSharedPreferences("shared_preferences", Context.MODE_PRIVATE);
}
public void save (String preference, boolean value) {
editor = preferences.edit();
editor.putBoolean(preference, value);
editor.apply();
}
public boolean boo (String preference) {
return preferences.getBoolean(preference, false);
}
public String is_second_activity_active = "is_second_activity_active";
}
You can now save the life cycles of your second activity by starting MyPreference
as follows:
public class ActivityTwo extends AppCompatActivity {
MyPreference p;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
p = new MyPreference(context);
// some source...
}
@Override
protected void onStart() {
super.onStart();
p.save(p.is_second_activity_active, true);
// your activity is active
}
@Override
protected void onStop() {
super.onStop();
p.save(p.is_second_activity_active, false);
// your activity is not active
}
}
You can understand the life cycle of the Activity
here
Finally, in your notification class, retrieve the status of your second activity:
// create notification
// ...
MyPreference p = new MyPreference(context);
Intent intent = new Intent
(context, p.boo(p.is_second_activity_active) ? ActivityTwo.class : ActivityOne.class);
// continue...
Sorry my English, i am not fluent. I hope you understand. I don't write in kotlin, so you can convert the code.
Let me know if it helped you. Thank you. > <
It is not possible to change the behavior of a notification after it has been created in one way. You can update the notification when circumstances change.
You need to define setOnlyAlertOnce (true)
in your NotificationCompat.Builder
, and then send a new notification with the same id
as the old notification.
If the id
is the same, and setOnlyAlertOnce (true)
, your notification will be updated without a pop-up, sound or vibration warning. You can use the same Builder for each update.
Although this works well, the documentation itself warns that if the notification is updated several times in a short period of time, some notifications will not be packaged.
Caution: Android applies a rate limit when updating a notification. If you post updates to a notification too frequently (many in less than one second), the system might drop some updates. Documentation
In your case, the notification would need to be updated whenever the user signs in and out of ActivityTwo.class
, and that would not be a good thing.
Alternatively, I recommend that you try this.
Instead of opening the activity directly by notification, open it from a BroadcastReceiver
,
and then decide which activity to open..
To broadcast your notification, your Intent needs to look like this
// create notification
// ...
Intent intent = new Intent();
intent.setAction(MyNotification.ACTION_OPEN);
intent.putExtra("get", "something");
// use getBroadCast instead of getActivity
PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pIntent);
// configure your builder normally
Now in your BroadcastReceiver
, make sure the user opened their notification, and what activity they were in when they did it.
public class MyNotification extends BroadcastReceiver {
public static String ACTION_OPEN = "com.example.intent.action.NOTIFICATION_OPEN";
@Override
public void onReceive(Context context, Intent intent) {
MyPreference m = new MyPreference(context);
boolean open_notification = ACTION_OPEN.equals(intent.getAction());
if (open_notification ) {
boolean is_active = m.boo(m.is_second_activity_active);
String log = is_active ? "Open in ActivityTwo" : "Open in ActivityOne";
Intent new_intent = new Intent(context, is_active ? two.class : one.class);
new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
new_intent.putExtra("get", intent.getExtras());
context.startActivity(new_intent);
Log.e("log", log);
}
}
}
If you prefer, use your method to find out if the user is in the second activity, or use the examples I mentioned earlier.
NOTE: The onStart () and onStop () methods are actually better than onResume () and onDestroy () to check if the user is still in the activity. onDestroy () is never called when the user closes the application, from recent applications.
Finally, declare your broadcast in your AndroidManifest.xml
<receiver android:name=".MyNotification"
android:exported="false">
<intent-filter>
<action android:name="com.example.intent.action.NOTIFICATION_OPEN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Do not forget add android:launchMode="singleTop"
to your ActivityOne
and ActivityTwo
The notification will open according to the user's activity, no matter where it was created.
Thus, if the activity is the only thing that changes, there is no need to update notifications whenever circumstances change.
It should work now. x-x