Opening app from push notification causes NullPointerException - codenameone

I have created an app using Codename One but I am having trouble with the push notifications on Android.
The issue happens when opening a push notification when the app isn't open in the background.
When it tries to use any resources from the theme it causes a NullPointerException. The theme is initialised in the init() method but doesn't appear to happen when opening the push notification.
If I then initialise the theme in the same method as the null pointer, just before it happens, it works. It then goes on to cause a null pointer further on in the method.
Why do some objects not appear to be initialised on android when opening a push notification when the app is not open in the background?
The line that originally causes the NullPointerException when using the theme is
Image icon = theme.getImage("ADINlogoRound.png");
My init method is
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
Resources css = null;
try {
css = Resources.openLayered("/theme.css");
} catch (IOException ex) {
}
UIManager.getInstance().addThemeProps(css.getTheme(css.getThemeResourceNames()[0]));
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
Log.bindCrashProtection(true);
Display.getInstance().lockOrientation(true);
}

It appears that in android the init and start methods are not called when the app is opened from a push notification. Whatever you do in those methods should also be done in the push method.

Related

How to detect URI activation on a WPF desktop package (WAP) after it has already launched?

I have a WPF desktop application that is MSIX-packaged using a Windows Application Package (WAP) project. I already know how to launch my WPF desktop app the first time using URI activation, by calling AppInstance.GetActivatedEventArgs() and then analyzing the arguments:
if (activatedEventArgs.Kind == ActivationKind.Launch)
{
if (((LaunchActivatedEventArgs)activatedEventArgs).Arguments == "myactivationcode")
// .. do something
}
But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched. This doesn't happen with UWP apps, just desktop apps. I can kill the 2nd instance to follow a desired singleton pattern, but what I want is for the first instance of my WPF app to get some event that lets it know to come back into view.
Things I've researched that have no answers that I can see:
How to handle URI activation in a Windows Application Packaging Project?
How can I handle file activation from a WPF app which is running as UWP?
https://learn.microsoft.com/en-us/windows/uwp/launch-resume/handle-uri-activation#step-3-handle-the-activated-event
Does any such API or event exist for URI re-activation? Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app? Any help here would be greatly appreciated.
But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched.
Whether a second instance is launched depends on the implementation of your custom Main method.
In your second link, there is a link to blog post and a code example that demonstrates how to prevent another instance from being launched.
It uses named pipes to communicate with the already running app instance and passes a serialized IActivatedEventArgs to it:
[STAThread]
static void Main(string[] args)
{
IActivatedEventArgs activatedEventArgs = AppInstance.GetActivatedEventArgs();
using (Mutex mutex = new Mutex(false, AppUniqueGuid))
{
if (mutex.WaitOne(0, false))
{
new Thread(CreateNamedPipeServer) { IsBackground = true }
.Start();
s_application = new App();
s_application.InitializeComponent();
if (activatedEventArgs != null)
s_application.OnProtocolActivated(activatedEventArgs);
s_application.Run();
}
else if (activatedEventArgs != null)
{
//instance already running
using (NamedPipeClientStream namedPipeClientStream
= new NamedPipeClientStream(NamedPipeServerName, AppUniqueGuid, PipeDirection.Out))
{
try
{
namedPipeClientStream.Connect(s_connectionTimeout);
SerializableActivatedEventArgs serializableActivatedEventArgs = Serializer.Serialize(activatedEventArgs);
s_formatter.Serialize(namedPipeClientStream, serializableActivatedEventArgs);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, string.Empty, MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
}
Does any such API or event exist for URI re-activation?
No
Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app?
Yes. Again, please refer to the mentioned blog post and accompanied code sample.

Check if user accepted a push notification permission in iOS in codenameone

How can I check if the user denied or accepted the push notification permission message in ios in codenameone or native?
Both Android and iOS have API's to detect if push is enabled:
Push Notification ON or OFF Checking in iOS
Android 4.1: How to check notifications are disabled for the application?
Since those were added relatively recently and we didn't get enough demand for that we don't support them at this time. You can probably invoke them with a native interface or submit a pull request with integration. Normally you would get a push registered callback when push works and an error or nothing if it doesn't.
I found a solution implementing a funtion native to IOS 10
This methods are working perfectly in Objective-c and codenameone code
//------------------------------------------------------------------------------
//This method is use to check if the user enable or disable push notification
//------------------------------------------------------------------------------
-(BOOL)isPushNotificationIsEnable{
if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]) {
NSLog(#"isPushNotificationIsEnable()->YES");
return YES;
} else {
NSLog(#"isPushNotificationIsEnable()->NO");
return NO;
}
}
//------------------------------------------------------------------------------
//This method is use to launch the Notification screen of your app
//------------------------------------------------------------------------------
Display.getInstance().execute("App-Prefs:root=NOTIFICATIONS_ID&path=your package name app", new ActionListener() {
String methodName = "startLocationSetting";
#Override
public void actionPerformed(ActionEvent evt) {
boolean status = Utils.isPushNotificationEnable();
}
});
//------------------------------------------------------------------------------

Video having problems on my phone in Codename One

I have created an app for video demonstration using Codename one. I'm Facing some challenges when I'm running the app on my Google Android Phone as it does not allow a full screen view and also after the video is done playing, it does not go back or restart the video again. Another problem was that I had a button at the bottom at the borderlayout and each time I click the button, it corrupts the video and the video won't play anymore. These are codes used for my demonstration app Demonstration App 1, Demonstration App2 .
#Override
protected void postMain1(Form f) {
final MediaPlayer mp = findMpPresent();
try {
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/sbuda.mp4");
if (is != null) {
mp.setDataSource(is, "video/mp4", null);
} else {
}
} catch (IOException ex) {
ex.getMessage();
}
}
This is a bit unclear since I can't see the stop/start etc with a GUI builder application.
You can use native on-device controls for playback using setFullScreen. Notice that this works nicely on the device but has no equivalent on the simulator.
Once playback is finished the media no longer exists as your input stream has been depleted. You will need to create a new Media object. You can use the completion callback (the Runnable argument) to detect the end of the media.

Codename One: Background Location Listener not firing on Android Lollipop

I'm building an app that should periodically capture the user's location (I'm looking for every 60 minutes), tracking the cities they've visited.
I first started off using the foreground location listener and it was perfect, it seems to fire every few minutes but I've put checks in place so that it only actually tracks a location if enough time has passed. When I switch to other apps it looks like the foreground listener will continue to fire for a period of time, and then just stop firing, which to me makes sense since I'm thinking the OS is backgrounding the app. At which point, I would expect the background listener to have been registered and wake the app when that listener is fired.
On to my question... I'm having trouble with the background location listener. I understand that it won't fire on simulator, but it's also not firing when I build debug (using built-in certificate) to my device. For the sake of this question I've distilled what my app is doing down to barebones, based off the example listed here: https://gist.github.com/shannah/86c739edac34216d3c4d
Just to be sure I tried switching the background listener to the standard foreground one (.setLocationListener(new BackgroundListener())), and running on the simulator, I can verify that my label gets updated with appropriate data.
I also had done some testing on my actual app where I would pop a dialog in the no-arg constructor to say the listener was initialized, and another dialog when locationUpdated was called. I was able to see the popup on init, but there was no dialog on locationUpdated, which led me to believe my device was never firing it.
The device I'm testing on is a Samsung S4 with Android 5.0.1 (Lollipop).
Here is the test application I wrote which closely mimics what my actual application is doing.
bglocation.java
package com.bglocation;
import java.util.List;
import com.codename1.io.Storage;
import com.codename1.location.LocationManager;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Label;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
/**
* This file was generated by Codename One for the purpose
* of building native mobile applications using Java.
*/
public class bglocation {
private Form current;
private Resources theme;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
}
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("Hi World");
LocationManager.getLocationManager().setBackgroundLocationListener(BackgroundLocationListener.class);
String lastCheckin = (String)Storage.getInstance().readObject("LOCATION");
String label = "No checkins.";
if (lastCheckin != null) {
label = lastCheckin;
}
Label hiLabel = new Label("Last checkin: " + label);
hi.addComponent(hiLabel);
hi.show();
}
public void stop() {
current = Display.getInstance().getCurrent();
}
public void destroy() {
}
}
BackgroundLocationListener.java
package com.bglocation;
import java.util.Date;
import com.codename1.io.Storage;
import com.codename1.location.Location;
import com.codename1.location.LocationListener;
public class BackgroundLocationListener implements LocationListener {
#Override
public void locationUpdated(Location location) {
Storage.getInstance().writeObject("LOCATION", new Date().toString());
}
#Override
public void providerStateChanged(int newState) { }
}
The background listener is invoked once there is a significant location change, it is also running on a completely different process so you don't really have a UI or access to your application instance.
What you need to do to communicate with your app is firing a local notification or launching an intent or storing the location into a file or a database and once your app is launched get the data from there.

Launching a CustomAction UI written with WPF from a WIX installer: Fail on STAThread issue

My WIX installer launches an immediate custom action.
The custom action starts a WPF dialog prompting the user for a BD connection parameters (I basically wrote the 'new connection' DB prompter dialog in WPF, to get me a connection string that the custom action can inject in the installed application's configuration file).
The WIX code is fairly simple to figure out, and I know I execute the custom action just fine - I put there a MessageBox and a MmsiBreak on the call to my custom action method. I get there without a problem.
When the custom action instantiates my WPF dialog window, I get an InvaliOperationException: "The calling thread must be STA, because many UI components require this".
The same code runs fine when I put it in a standard WPF application, because VisualStudio generates boiler plate code with Main() that has a STAThreadAttribute on it.
I can't tack that attribute on the msiexec caller, and if I try to set the thread apartment state in my custom action, it fails:
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Is not supposed to work for framework past 2.0.
Is there any way to do what I'm trying to do here? I'd appreciate some pointers.
EDIT
I even tried to run the dialog in its own thread, e.g. the code is like this:
// Static class members
static ManualResetEvent _done = new ManualResetEvent(false);
static ActionResult _caResult;
static Session _session;
static Thread _worker;
[CustomAction]
static public ActionResult PromptForDB(Session session)
{
_session = session;
_worker = new Thread(WorkerThread);
_worker.Start();
_done.WaitOne();
return _caResult;
}
[STAThread]
static void WorkerThread()
{
try
{
Prompter wnd = new Prompter();
if (!(bool)wnd.ShowDialog())
{
_caResult = ActionResult.SkipRemainingActions;
}
else
{
// Harvest our properties (omitted from this post)
_caResult = ActionResult.Success;
}
catch (Exception ex)
{
_caResult = ActionResult.Failure;
_session.Log("Error: " + ex.Message);
}
finally
{
_done.Set();
}
}
That does not work either.
Before starting your new thread, set its ApartmentState as follows:
_worker.SetApartmentState(ApartmentState.STA);
See this:
The calling thread must be STA, because many UI components require this in WPF

Resources