Codename One: Background Location Listener not firing on Android Lollipop - codenameone

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.

Related

Element not found. How to test sequence of steps in multi-page WPF app with winappdriver?

I have a WPF application that features several pages. Navigation takes place after selecting some of the buttons. I am able to start the testing session successfully and to find elements in the main window. However, when clicking the "OK" button that should trigger navigation to another page, the app does not navigate and the test case fails to find UI elements in the next page. I have tried ImplicitWait and Thread.Sleep but the elements still cannot be found. It seems like the app does not navigate at all when the button is clicked.
Any ideas on how to tackle this issue? Below is what I have accomplished so far:
namespace TestDAAC
{
[TestClass]
public class UnitTests
{
protected const string WINAPPDRIVER_URL = "http://127.0.0.1:4723";
private const string DAAC_APP_ID = #"C:\Users\Admin\Desktop\VC PROJECTS\daac\DAAC\bin\x64\Release\DAAC5.exe";
protected static WindowsDriver<WindowsElement> daacSession;
[ClassInitialize]
public static void Setup(TestContext context)
{
if (daacSession == null)
{
var appiumOptions = new AppiumOptions();
appiumOptions.AddAdditionalCapability("app", DAAC_APP_ID);
appiumOptions.AddAdditionalCapability("deviceName", "WindowsPC");
daacSession = new WindowsDriver<WindowsElement>(new Uri(WINAPPDRIVER_URL), appiumOptions);
}
}
[TestMethod]
public void SequenceOfSteps()
{
daacSession.FindElementByName("OK").Click();
Thread.Sleep(5000);
// daacSession.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
daacSession.FindElementByName("New Imaging Session").Click();
}
}
}
I was able to find the reason why my test cases were not working. WinAppDriver is compatible only with Windows 10 Home or Pro. My target device runs on Windows Enterprise.

Server Sent Events Not Working Using JavaFX WebView

I have developed a single page application with React and MobX. To get some progress information from backend code such as copying a file progress, I use Server Sent Events and EventSource at javascript code. In any browser, I can get the event messages and show progresses successfully. React gets changes from the EventSource onmessage event and renders the changes on the screen. Here is how I add EventSource to my js code. (For the ones who ask if the message format of eventsource is correct? Yes, it is. It is working on browsers.)
Code:
fetchEvents(url) {
let evtSource = new EventSource(url);
evtSource.onmessage = (message) => {
const data = JSON.parse(message.data);
//assign data to an observable variable
}
}
However, I need my single page application to be embeded in a Java application. For this, I use JavaFX WebEngine and WebView to load my React application. Every functionalities work well except Server Sent Events and EventSource messages. onmessage(), onopen(), onerror() methods are not called. Thus, I can't get the changes of data to be shown on the screen. I can't get any information via EventSource at my javascript code. Here is the JavaFX code;
Code:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("localhost");
WebView myBrowser = new WebView();
WebEngine myWebEngine = myBrowser.getEngine();
myWebEngine.setJavaScriptEnabled(true);
myWebEngine.load("http://localhost:8080");
StackPane root = new StackPane();
root.getChildren().addAll(myBrowser, reloadButton);
primaryStage.setScene(new Scene(root, 800, 640));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Does JavaFX WebView not support EventSource and Server Sent Events? I am curious about is there any way to make SSE work in JavaFX WebView? Or are there any other possible solutions to embed my single page application in Java code with EventSource and Server Sent Events working well.
Thank you.

CodeName One error: cannot find symbol

I have created a simple sample Application with CodeNameOne without any changes.
Certificate and Provisioning file is available and configured as project properties.
IDE: Eclipse
Desktop OS: Windows
Executing 'Send IOS Debug Build' starts the server build and shows the
following error:
/var/folders/p7/d3z112yd0156kxkm2p21p8ym0000gn/T/build5327647990993852705xxx/stub/TestBuildDeployStub.java
/var/folders/p7/d3z112yd0156kxkm2p21p8ym0000gn/T/build5327647990993852705xxx/stub/TestBuildDeployStub.java:14:
error: cannot find symbol private TestBuildDeploy i;
^ symbol: class TestBuildDeploy location: class TestBuildDeployStub
/var/folders/p7/d3z112yd0156kxkm2p21p8ym0000gn/T/build5327647990993852705xxx/stub/TestBuildDeployStub.java:23:
error: cannot find symbol i = new TestBuildDeploy();
^ symbol: class TestBuildDeploy location: class TestBuildDeployStub Note:
/var/folders/p7/d3z112yd0156kxkm2p21p8ym0000gn/T/build5327647990993852705xxx/stub/TestBuildDeployStub.java
uses or overrides a deprecated API. Note: Recompile with
-Xlint:deprecation for details. 2 errors
This is the java class:
package com.canda.mario.myapp;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.Label;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.Toolbar;
import java.io.IOException;
/**
* This file was generated by Codename One for the purpose
* of building native mobile applications using Java.
*/
public class TestBuildDeploy {
private Form current;
private Resources theme;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature, uncomment if you have a pro subscription
// Log.bindCrashProtection(true);
}
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("Hi World");
hi.addComponent(new Label("Hi World"));
hi.show();
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
If you change the package/class of a Codename One application after it's created you need to change it everywhere both in the project and in the codenameone_settings.properties that is why we recommend never changing it.
We don't make this process easy since you are married to life when creating a package name. This is used to uniquely identify you in the stores and can't be changed ever once an app is submitted so you need to understand that this isn't something you should do... Give package name deep consideration before creating the app!

Why Doesn't My Component Appear On Top of The HTML Page Or Media Player In Codename One

I've used a media player and I'm trying to do rendering on top of it with progress indication or buttons but the code isn't working.
E.g.:
findInfiniteProgress().setVisible(true);
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
if(findMediaPlayer().getMedia() != null && findMediaPlayer().getMedia().isPlaying()){
findInfiniteProgress(f).setVisible(false);
}else{
findInfiniteProgress(f).setVisible(true);
}
}
});
}
};
Codename One uses lightweight rendering which means all components are drawn in sequence on a single thread. Native widgets (peers) need to be drawn on the native thread and are always drawn on top, that is the secret to Codname Ones portability explained here.
Common peers in Codename One include: Web browser, media playback & native maps.
The workaround is to use Dialog which is effectively a separate Form so the current peer doesn't really render underneath.

JDO Loading Inconsistencies on Google App Engine

I've been following the app engine JDO documentation as closely as possible, but I'm having bizzare and inconsistent trouble loading a persistent collection that is contained by my Board object. The inconsistency occurs even in the local Development Webserver after I manually specify "eventual consistency" as being nonexistent.
Sometimes when I load my object/collection using the loading helper methods I've created, it loads no problem. Other times an empty collection is returned (please note that I am "touching" the collection with a getter method to ensure the data is not just a lazy loaded into a proxy object).
Initially I thought the problem was simply related due to the High Replication Storage engine's "eventual consistency" drawbacks, but after making my own policy with 0% eventual consistency in the LocalServiceTestHelper, I'm fairly certain that's not the case.
I've created a JUnit test that exemplifies this problem. Basically, I attempt to create and save a dummy User and Board object in the testInsertUser function. I attach a newly created ArrayList of PlayedTile objects to this board, and then execute a DataMaster.saveUser helper method which uses Google App Engine's persistence manager to save the User (and thus the Board and PlayedTile collection) to the datastore. In the next method, we attempt to load that User (with its Board and PlayedTile collection) and display those saved results. Chaos ensues.
Here is the JUnit code:
package com.astar.wordswall.test.data;
import java.util.ArrayList;
import com.astar.wordswall.data.DataMaster;
import com.astar.wordswall.data.jdo.Board;
import com.astar.wordswall.data.jdo.User;
import com.astar.wordswall.data.jdo.PlayedTile;
import com.astar.wordswall.test.appengine.LocalCustomHighRepPolicy;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
// import com.google.gwt.user.client.Random;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class SaveUsersBoardWithTilesTest {
Key userKey;
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setAlternateHighRepJobPolicyClass(LocalCustomHighRepPolicy.class));
#Before
public void setUp() {
helper.setUp();
}
#After
public void tearDown() {
helper.tearDown();
}
#Test
public void testInsert1() {
testInsertUser();
testReadUser();
}
/**
* Creation and insertion of a user, board, and linked set of tiles into BigTable.
*/
private void testInsertUser() {
User u = new User("Simon");
Board b = new Board();
ArrayList<PlayedTile> tiles = new ArrayList<PlayedTile>(7);
u.setBoard(b);
b.setPlayedTiles(tiles);
for (int j = 0; j < 7; j++) tiles.add(new PlayedTile('T'));
DataMaster.saveUser(u);
// Retrieve the user's key so that we can read him from the database later
userKey = u.getUserKey();
// Display all of our saved tiles:
System.out.println("Saved tiles:");
// Note that "getTileString()" just iterates through each Played tile printing the letter
System.out.println("\t" + u.getBoard().getTileString());
}
/**
* A typical read of a user object from the Datastore.
*/
private void testReadUser() {
User u = DataMaster.getUserWithBoard(userKey);
// Display all of our saved tiles:
System.out.println("Loaded tiles:");
System.out.println("\t" + u.getBoard().getTileString());
}
}
And here's the relevant DataMaster.getUserWithBoard static function that actually performs the JDO loading:
/**
* Loads a uniquely specified User and their associated board from
* the Datastore. It also loads the board's complete list of PlayedTiles.
* #param userKey the unique key assigned to this user
*/
public static User getUserWithBoard(Key userKey){
User u = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
u = pm.getObjectById(User.class, userKey);
// In order for the board and tile collection to load, we must "touch" it while PM is active
if (u.getBoard().getPlayedTiles().size() != 0) u.getBoard().getPlayedTiles().get(0);
if (u.getBoard().getPlayedWords().size() != 0) u.getBoard().getPlayedWords().get(0);
} finally{
pm.close();
}
return u;
}
Oddly enough, this code SOMETIMES works as expected: it prints out the exact same set of tiles it saves after it loads them from the datastore in testReadUser(). SOMETIMES it just loads an empty collection, although what's particularly bizzare is that the u.getBoard().getPlayedWords().get(0) call doesn't throw a null pointer exception.
The output oscillates between
Correct:
Saved tiles:
T T T T T T T
Loaded tiles:
T T T T T T T
And Incorrect:
Saved tiles:
T T T T T T T
Loaded tiles:
totally haphazardly.
Can anybody out there shine some light on this? It's driving me completely crazy. :)
EDIT: Another bizzare clue/factoid is that if I make the whole test iterate by enclosing both the testSaveUser and testReadUser method calls in a for loop, either EVERY load operations executes correctly, or NONE of them do. Is this a bug in the Local Google App Engine testing environment?
Just to check: Did you mark your data classes as detachable? I.e.
#PersistenceCapable(detachable = "true")
public class Board { /* fun stuff here */ }
Also, it might be helpful to look at the datastore viewer to see if really worked or not: http://localhost:8888/_ah/admin/

Resources