I'm writing a native Android code to open my app when a notification is pressed. If the app is already opened (whether running in foreground or in background), I want clicking the notification to bring the app to front, without restarting it, so that its state is preserved.
I tried the following code (showing only relevant code):
///////// Create an activity on tap (intent)
const Intent = android.content.Intent;
const PendingIntent = android.app.PendingIntent;
// Create an explicit intent for an Activity in your app
const intent = new Intent(context, com.tns.NativeScriptActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
const pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
///////// Creating a notification
var NotificationCompat = android.support.v4.app.NotificationCompat;
const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.btn_star_big_on)
.setContentTitle(title)
.setContentText(message)
.setStyle(
new NotificationCompat.BigTextStyle()
.bigText("By default, the notification's text content is truncated to fit one line.")
)
.setPriority(NotificationCompat.PRIORITY_HIGH)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);
///////// Show the notification
notificationManager.notify(NOTIFICATION_ID, builder.build());
But that opened the application without preserving its state.
Following recommendations here, I also tried emulating pressing the app icon from the launcher - so that the app is just brought to the frontground and the Nativescript activity is not recreated.
const packageName = context.getPackageName();
console.log('Package name: ',packageName);
const emulateLaunchByAppIconIntent = context.getPackageManager()
.getLaunchIntentForPackage(packageName)
.setPackage(null)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
const pendingIntent_emulated = PendingIntent.getActivity(context, 0, emulateLaunchByAppIconIntent, 0);
///////// Creating a notification
var NotificationCompat = android.support.v4.app.NotificationCompat;
const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.btn_star_big_on)
.setContentTitle(title)
.setContentText(message)
.setStyle(
new NotificationCompat.BigTextStyle()
.bigText("By default, the notification's text content is truncated to fit one line.")
)
.setPriority(NotificationCompat.PRIORITY_HIGH)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent_emulated)
.setAutoCancel(true);
///////// Show the notification
notificationManager.notify(NOTIFICATION_ID, builder.build());
This indeed made the app come to front, but didn't preserve its state (even if the app was already in foreground - it reloaded the app).
Then I tried pressing a Nativescript application app icon (manually), when the app has just been sent to the background - and I found that it would restart the app, and not just bring it to the foreground.
My question is - why does a Nativescript application behave like this?
How can I make Android just bring the app to foreground and not re-build a new nativescript activity?
The code in the question above, actually works - and does bring the app to the foreground without restarting the app, preserving its state.
The reason the app was restarting, even by clicking the Nativescript application app icon (manually) was related to the development environment.
This happened when I was running the app on a physical device while connected to my Mac running tns run android --bundle, or
Running the app in an emulator (either by running tns run android --bundle or by launching the app directly from the app icon)
Running the app on a physical device that is not connected to the nativescript development environment - showed the real behavior - and the app was brought to the foreground without restarting after clicking the notification.
More info with code examples:
I found that there's no need to launch the app by simulating an icon press using this code
const emulateLaunchByAppIconIntent = context.getPackageManager()
.getLaunchIntentForPackage(packageName)
.setPackage(null)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
const pendingIntent_emulated = PendingIntent.getActivity(context, 0, emulateLaunchByAppIconIntent, 0);
as PendingIntent.FLAG_UPDATE_CURRENT or Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED in the code below, is sufficient to bring app to the foreground without restarting after clicking the notification:
const openActivityIntent = new Intent(context, com.tns.NativeScriptActivity.class);
openActivityIntent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
const openActivityPendingIntent = PendingIntent.getActivity(context, 0, openActivityIntent, 0);
///////// Creating a notification
const notificationManager = <NotificationManager> context.getSystemService(NotificationManager.class);
var NotificationCompat = android.support.v4.app.NotificationCompat;
const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSound(soundUri)
.setSmallIcon(android.R.drawable.ic_lock_idle_alarm)
.setContentTitle(title)
.setContentText(message)
.setStyle(
new NotificationCompat.BigTextStyle()
.bigText('More explaination text if needed. Disabled for now.')
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(openActivityPendingIntent)
.setWhen(scheduledTime)
.setAutoCancel(true)
.build();
///////// Show the notification
notificationManager.notify(NOTIFICATION_ID, builder);
Hope this helps you if you got into the same issue.
Related
I'm trying to open 2 AppWindows (appWindowOne & appWindowTwo) on separate monitors in full screen but when appWindowTwo opens appWindowOne minimizes. I've tried making the AppWindow re-enter full screen programmatically but it causes the other AppWindow to minimize. When manually clicked in the taskbar it restores to full screen without affecting the other but I would like to know if it's possible to do it programmatically?
public static async void ShowAppWindows()
{
AppWindow appWindowOne = await AppWindow.TryCreateAsync();
Frame frameOne = new Frame();
ElementCompositionPreview.SetAppWindowContent(appWindowOne, frameOne);
AppWindow appWindowTwo = await AppWindow.TryCreateAsync();
Frame frameTwo = new Frame();
ElementCompositionPreview.SetAppWindowContent(appWindowTwo, frameTwo);
FullScreenPresentationConfiguration FSPC = new FullScreenPresentationConfiguration()
{
IsExclusive = false
};
await appWindowOne.TryShowAsync();
appWindowOne.RequestMoveToDisplayRegion(displayRegions[0]);
appWindowOne.Presenter.RequestPresentation(FSPC);
await appWindowTwo.TryShowAsync();
appWindowTwo.RequestMoveToDisplayRegion(displayRegions[1]);
appWindowTwo.Presenter.RequestPresentation(FSPC);
}
. I've tried making the AppWindow re-enter full screen programmatically but it causes the other AppWindow to minimize.
This looks UI-thread was broken when make appWindowTwo into full screen. I guess setting two windows in a row in full screen will exhaust the UI thread. So, we could try to call a Task.Delay() before making appWindowTwo into full screen.
I have been working on an application that uses both forms and native in Xamarin. The app starts with the form and switch to native to open the camera. My problem is once the image is clicked I want to go back to Forms application but I am unable to find enough documentation on it.
I have tried Navigation.PushAsync in iOS but it doesnt work.
var videoConnection = stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);
var jpegImage = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
var photo = new UIImage(jpegImage);
byte[] data;
NSData imageData = photo.AsJPEG();
data = new byte[imageData.Length];
EnrollImageDisplay.ImageData = data;
Where EnrollImageDisplay is my content page in forms. Not I have to call this page but I am unable to do so. Any solution with this?
EDIT: Solved it using Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new Page());
I want to set animation on Notification Badge and how to display the badge infront of the imageview(Z axis)
According to the following thread, we can see that Android does not allow changing of the application.
How to display count of notifications in app launcher icon
But If you still want to animation for notification, I suggest you can implement animation for Android Notification bar.
It needs one animationfile.xml
<?xml version="1.0" encoding="utf-8" ?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/icaon" android:duration="10000" />
<item android:drawable="#drawable/ic_stat_button_click" android:duration="10000" />
</animation-list>
int icon = Resource.Drawable.animationfile;
// Build the notification:
var builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.SetAutoCancel(true) // Dismiss the notification from the notification area when the user clicks on it
.SetContentIntent(resultPendingIntent) // Start up this activity when the user clicks the intent.
.SetContentTitle("Button Clicked") // Set the title
.SetNumber(count) // Display the count in the Content Info
//.SetSmallIcon(Resource.Drawable.ic_stat_button_click) // This is the icon to display
.SetSmallIcon(icon)
.SetContentText($"The button has been clicked {count} times."); // the message to display.
// Finally, publish the notification:
var notificationManager = NotificationManagerCompat.From(this);
notificationManager.Notify(NOTIFICATION_ID, builder.Build());
Here is the same thread, you can take a look:
How to blink notification icon in android? [DONE]
Following the Embarcadero docs at this link i'm testing notifications on iOS (in FMX app built with C++). I've done the follownig:
Added #include <System.Notification.hpp> to the header file
Set FMLocalNotificationPermission to true
Dropped TNotificationCenter component on the form
Then, i put the following code in a button click:
void __fastcall TForm1::ScheduleNotificationClick(TObject *Sender)
{
if (NotificationCenter1->Supported()) {
TNotification *myNotification = NotificationCenter1->CreateNotification();
__try {
myNotification->Name = "MyNotification";
myNotification->AlertBody = "C++ for your mobile device is here!";
// Fire in 10 seconds
myNotification->FireDate = Now() + EncodeTime(0, 0, 10, 0);
// Send notification to the notification center
NotificationCenter1->ScheduleNotification(myNotification);
}
__finally {
myNotification->DisposeOf();
}
}
}
Once in a while it works...but rarely and never more than once. Most of the time it doesn't at all (repeated deleting and reinstall of app).
Next, i tried the "Present the Notification Message Immediately" code they provide:
void __fastcall TForm1::PresentNotificationClick(TObject *Sender)
{
if (NotificationCenter1->Supported()) {
TNotification *myNotification = NotificationCenter1->CreateNotification();
__try {
myNotification->Name = "MyNotification";
myNotification->AlertBody = "C++ for your mobile device is here!";
// Set Icon Badge Number (for iOS) or message number (for Android) as well
myNotification->Number = 18;
myNotification->EnableSound = False;
// Send notification to the notification center
NotificationCenter1->PresentNotification(myNotification);
}
__finally {
myNotification->DisposeOf();
}
}
}
Nothing happens at all with this code. I've tried this from scratch several times and i'm as sure as i can be that i'm coding it per their examples. I'm using 10.3 (Embarcadero® C++Builder 10.3 Version 26.0.32429.4364). I would think my code has a problem except once in blue moon it works.
My target is iPhone running 12.1.4 and i've tried building with SDK11.4 and SDK12.0, no difference. When i first run app i get the "allow or don't allow" popup and my app subsequently shows up in the Notification settings - just doesn't work.
russ
UPDATE 3-25-2019: If I run that top block of code (from a button click on iPhone) it will now run everytime - but ONLY IF i immediately kill the app after clicking. 10 seconds later it fires the notification. Why won't the notification appear if i leave my app running??
Are you sure you are calling "PresentNotificationClick" from the TButton when you click it?
I've been looking for a way to show an offline (not pushed from a server) toast notification on WP7 for a while now. Any ideas?
If you're trying to show the notification while your application is running, you can use the ToastPrompt from the coding4fun toolkit: http://coding4fun.codeplex.com/
If you want to show the notification while your app isn't running, you can use the ShellToast class from a background agent: http://msdn.microsoft.com/en-us/library/microsoft.phone.shell.shelltoast(v=vs.92).aspx
Within a background task, simply call this method:
public static void makeToast(string toastText)
{
//Make a new toast with content "text"
ShellToast toast = new ShellToast();
toast.Title = "Toast Title: ";
toast.Content = toastText;
//toast.NavigationUri = new Uri();
toast.Show();
}