LocalNotification setId() behavior [codenameone] - codenameone

Is LocalNotification Id suppose to be displayed in ToastBar?
I created a Local notification:
LocalNotification ln = new LocalNotification();
ln.setId("geofence entered");
ln.setAlertTitle("Welcome");
ln.setAlertBody("Please proceed to the building");
Display.getInstance().scheduleLocalNotification(ln,
System.currentTimeMillis() + 1000, LocalNotification.REPEAT_NONE);
It fires properly and shows me a notification with correct Title and Body. However, if I click on it, when it opens the app - the Id "geofence entered" is displayed in ToastBar. If I remove .setId("geofence entered"), the notification is not shown and I get an error:
2021-07-13 17:15:40.009 21809-21809/io.jarvisapp.app E/Codename One: background location error
java.lang.IllegalArgumentException: Notification ID must be set
at com.codename1.ui.Display.scheduleLocalNotification(Display.java:4804)
at io.jarvisapp.app.geofence.GeofenceListenerImpl.onEntered(GeofenceListenerImpl.java:131)
where line 131 is Display.getInstance().scheduleLocalNotification(ln, System.currentTimeMillis() + 1000, LocalNotification.REPEAT_NONE);
How can I not display the id in ToastBar?
Thank you in advance.

The piece of code that was causing the issue was found, thanks to #Shai comment about the callback code.
I completely forgot that I implemented LocalNotificationCallback with the following method in my main class:
#Override
public void localNotificationReceived(String notificationId) {
GeneralUtil.showToastBarMessage(notificationId,3000,0);
}

Related

Can't see system.debug ouput in logs when using apex batchable code

I execute the following in the anonymous execution:
Database.executeBatch(new TransferACDCAccountOppOwnerBatch(), 200);
The class is below. It uses Batchable interface. I put in a bunch of debug statements but don't see anything in the logs in the console. I also create debug logs at Debug level for Apex, etc. and also don't see any of the system.debug output. The SOQL itself I know works and should only return one row in the developer sandbox test data I setup.
Is there something about the batchable interface that doesn't allow system.debug output? I know it's asynchronous, but the job completes and I see plenty of log information. I just don't see any system.debug output.
global class TransferACDCAccountOppOwnerBatch implements Database.Batchable<sObject> {
String query;
static String type = 'Accountant';
static String stageName = 'Closed Won';
static String numberEmployees = '<5';
global TransferACDCAccountOppOwnerBatch() {
query = 'SELECT Id, Num_Active_Orgs__c, Num_Active_Paying_Orgs__c,Number_of_Bookkeeping_Clients__c, Number_Bookkeeping_Clients_SR__c,' +
'Num_Targeted_Orgs__c, AccountId, Account_State__c, Biz_Dev_Owner__c,CloseDate, IsClosed, Name, Type, OPS_ID__c, Org_Creator__c,' +
'Org_s_Geographical_State__c, OwnerId, StageName, Tier__c, IsWon,First_targeted_Org__r.NumberEmployees__c, Account.name, Account.owner.name' +
' FROM Opportunity' +
' WHERE StageName = :stageName' +
' And type = :type' +
' And CloseDate < Last_90_Days' +
' And First_targeted_Org__r.NumberEmployees__c = :numberEmployees';
}
global Database.QueryLocator start(Database.BatchableContext BC) {
System.debug('start query');
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Account> scope) {
System.debug('execute batch transfer');
TransferACDCAccountOppOwnerHandler hierarchy_handler = new TransferACDCAccountOppOwnerHandler();
hierarchy_handler.setup(scope, BC.getJobId());
System.debug('after hierarchy handler setup');
// hierarchy_handler.runMatching();
// hierarchy_handler.processConsoles();
// hierarchy_handler.processGlobalConsoles();
// hierarchy_handler.commitUpdates();
}
global void finish(Database.BatchableContext BC) {
System.debug('finish bath');
}
}
Debug logs are limited to 2MB if they go over that size salesforce unhelpfully remove debug lines in an attempt to reduce the size to below the limit.
If you have a particularly noisy class you can override the logging for that class.
Check out the documentation here: https://help.salesforce.com/articleView?id=code_setting_debug_log_levels.htm&type=0&language=en_US&release=206.20
A quick and easy hack that I sometimes use would be to set your debog levels to ERROR, and then every time you want to debug you just do
System.debug(LoggingLevel.ERROR, 'Debug message goes here');
Just don't forget to clear your debug lines when you're done, so as not to make the problem worse going forward.
Turns out that in the Execute method I was passing List instead of List while the query was against Opportunity.
Also, seems like setting LoggingLevel.INFO helps at least with getting debug messages sent to developer console when running this batchable class in anonymous execution.
Thanks for the tips!
System.dubug is supported in batch apex.
As batch apex runs asynchronously, so it creates multiple logs based on your batch size. So, look at every log file that is created when batch apex completed its execution.

Image always missing in the received message while sharing an image in Codename One

I am generating an image that is saved in FileSytemStorage.getAppHomePath() dir. I now need to share it via Email, SMS ... That's why I am using the following code (based on Codename One documentation) in my action method :
long time = new Date().getTime();
String fullOutputPath = FileSystemStorage.getInstance().getAppHomePath()
+ "Montage_" + Long.toString(time) + ".png";
// Save the image with the ImageIO class
try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(fullOutputPath)){
ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_PNG, 1.0f);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Enable image sharing (outside the try/catch so that the outputstream in closed for sure)
if (FileSystemStorage.getInstance().exists(fullOutputPath)) {
Dialog.show("Saved", "Photo collage saved to " + fullOutputPath
+ " (file size = " + FileSystemStorage.getInstance().getLength(fullOutputPath) +" B)", "OK", null);
//Photo collage saved to file://home/Montage_14669... .png (file size = 50387B)
findValidateMontageShareButton3().setImageToShare(fullOutputPath, "image/png");
// Null pointer exception
So in that way I get a NPE and if I don't test if the file does exist there is no NPE but the image is still missing (both in the simulator and on the device).
The stack trace is as follows :
java.lang.NullPointerException
at userclasses.StateMachine.onPage3_ValidateMontageShareButton3Action(StateMachine.java:852)
at generated.StateMachineBase.handleComponentAction(StateMachineBase.java:757)
at com.codename1.ui.util.UIBuilder$FormListener.actionPerformed(UIBuilder.java:2835)
at com.codename1.ui.util.EventDispatcher.fireActionSync(EventDispatcher.java:459)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:362)
at com.codename1.ui.Button.fireActionEvent(Button.java:411)
at com.codename1.ui.Button.released(Button.java:442)
at com.codename1.ui.Button.pointerReleased(Button.java:530)
at com.codename1.ui.Form.pointerReleased(Form.java:2627)
at com.codename1.ui.Form.pointerReleased(Form.java:2563)
at com.codename1.ui.Component.pointerReleased(Component.java:3158)
at com.codename1.ui.Display.handleEvent(Display.java:2025)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1067)
at com.codename1.ui.Display.mainEDTLoop(Display.java:996)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
It looks that the file my app is generating is not accesible to the sharing app. Do I have to add any extra permission as advised here for Android ?
Please note : I don't know if it is related to this problem but I cannot access to Codename One Settings menu from Eclipse anymore (maybe since upgrade to CN1 lib v 115)
Any help appreciated,
Cheers
So here is part of the answer which works in the simulator (ie the image appears in the fake email client => see image below).
So it appears that the share button cannot be set up in the action method (ie the method that is triggered when the user click on the share button). It has to be set up previously.
Consequently, in the beforeShow method my code reads as follows :`
FontImage.setMaterialIcon(findValidateMontageShareButton3(), FontImage.MATERIAL_CHECK_CIRCLE);
final long time = new Date().getTime();
// We generate the montage filename JPG otherwise it cannot be sent
montage.setMontageFullPath(FileSystemStorage.getInstance().getAppHomePath()
+ "Montage_" + Long.toString(time) + ".jpg");
// We assign the montage filename to the share button BEFORE we can click the button (otherwise the
// filename cannot be taken into account)
findValidateMontageShareButton3(f).setImageToShare(
montage.getMontageFullPath(), "image/jpeg");
Then in the onAction method related to the share button the code reads :
// Save the image with the ImageIO class
// We wait until the file is completely written to continue
Display.getInstance().invokeAndBlock(new Runnable() {
#Override
public void run() {
try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(montage.getMontageFullPath())){
ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_JPEG, 1);
} catch (IOException e) {
Dialog.show("Erreur", "Impossible de sauvegarder le montage! Merci de vérifier l'espace disque disponible.", null, "OK" );
}
}
});
I tested it and it worked on the simulator but not on the device. Either with a png or a jpeg file, the file cannot be attached to the SMS or email (Android error message "abnormal file, can't attached file").
However if I do it a second time, then the file can be attached. So now the image is not missing but it cannot be attached (the first time) which is still embarrassing.

Closing the New Window on a new Thread (WPF)

Hi I had posted a question along these lines recently but this is now a little more specific to my requirements. So, I have an Application where the user needs to log in. The log in process can take some time so I decided to put up a little animated GIF to show it is doing something. Sounds simple...!!??
I noticed soon that the login process was freezing the animation so I thought, I will put the login process on its own thread. I had countless instances of it referencing objects on the UI Thread so thought I would try the other way round and have the Image display on a new thread. Same issue - so I decided to create a new window containing the image, format it accordingly and display this as a new thread! Simple! That (bit) worked... I click to login, animation appears and disappears onces login is complete. So the Thread variable is set as global one:
Friend g_thLoading As Thread
And when the Login button is clicked I have the following:
g_thLoading = New Thread(AddressOf LoginSplashScreen)
g_thLoading.SetApartmentState(ApartmentState.STA)
g_thLoading.IsBackground = True
g_thLoading.Name = "LoginThread"
g_thLoading.Start()
VerifyLogin() 'Process that takes a while...
g_thLoading.Abort()
Then the method that is called in the new thread:
Sub LoginSplashScreen()
Dim SplashScreenWin As New SplashScreen()
Try
SplashScreenWin.ShowDialog()
System.Windows.Threading.Dispatcher.Run()
Catch ex As Exception
SplashScreenWin.Close()
SplashScreenWin = Nothing
End Try
End Sub
This works - but not if I have to click the button more than once. However If (for example) the user enters the wrong credentials, clicks login (the above processes and completes) they are prompted to re-enter - click the login button again... but this time, the window doesnt display (but oddly does appear in the Task Bar)... Then the application is forced to close (nothing in debug on why that is).
I am confident that the Dialogue Window is closing correctly after the first instance as i) it is no longer in the Task Bar and secondly I have put some checks on the Windows Close event. I am fairly confident that the created Thread is closed after the first instance as I can see it drop off from the Thread Window in Visual Studio... So - I am at a total loss. I have also tried the Join function on the thread but this just hangs the process before it gets to g_thLoading.Abort()
I am open to any advice on how I can go about achieving my end goal... whether it is expanding on what I have done here or another suggestion altogether. I have messed around with the Background Worker but not had much more luck there.
Use the BackgroundWorker class to implement your long running processes. The class allows you to specify code that will run on a background thread (in the DoWork event handler), code that will run during "updates" on the thread that created the BackgroundWorker in the ProgressChanged event handler, and code that will run when the process completes, again on the thread that created the BackgroundWorker in the RunWorkerCompleted event handler.
Using it goes something like this:
private class LoginParameters {
public string Name { get; set; }
public string Password { get; set; }
// Any other properties needed
}
// Make this a property of your form.
BackgroundWorker LoginWorker { get; set; }
// Somewhere in your UI code after the user clicks the "login button"
LoginWorker = new BackgroundWorker();
LoginWorker.WorkerReportsProgress = true;
LoginWorker.WorkerSupportsCancellation = true; // Can set to false if you don't allow the operation to be cancelled.
LoginWorker.DoWorker += DoLogin;
LoginWorker.ProgressChanged += ReportProgress;
LoginWorker.RunWorkerCompleted += LoginFinished;
LoginParameters login = new LoginParameters {
// Code to initialize everything here
};
LoginWorker.RunWorkerAsync(login);
// Put this in the click event handler for the Cancel button, if you have one
if ( LoginWorker != null )
LoginWorker.CancelAsync();
private void DoLogin(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = (BackgroundWorker) sender;
LoginParameters login = (LoginParameters) e.Argument;
// Your logic to process the login goes here. It should periodically do the following to check to see if the user clicked the cancel button:
if ( worker.CancellationPending ) {
e.Cancel = true;
return;
}
// When you want to update the UI, do this:
worker.ReportProgress( percentComplete, objectWithOtherDataToWriteToTheUI );
// When you're done, just return.
}
private void ReportProgress(object sender, ProgressChangedEventArgs e) {
// Your code to extract the data you need to update the display from the arguments & to then update the display goes here. Remember, this runs on the UI thread
}
private void LoginFinished( object sender, RunWorkerCompletedEventArgs e ) {
if (e.Cancelled == true)
// Your code to inform the user of the cancellation here
else if (e.Error != null)
// All unhadgled exceptions throws by the DoWork event handler end up here
// Your code to inform the user of the error here
else {
// Your code to inform the user of the success goes here.
// Remember, this runs on the UI thread.
// I recommend you set the form BackgroundWorker property to null after its finished, as you can't reuse it after its finished.
LoginWorker = null;
}
}
Sorry this is in C# if you're looking for VB.NET, but it shouldn't be hard to translate.

Behat, PhantomJS - wait for page load after clicking link?

I'm using Behat 3 and PhantomJS 2. Currently I have a scenario defined as such:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
Then I should be on "/path-to-page"
When I run this with Goutte it's fine. When I run this with vanilla Selenium, it's fine (it launches a browser I can see). However, when I configure Selenium to point the webdriver host to PhantomJS, it explodes on Then I should be on "/path-to-page" claiming it's still on /.
If I add the following wait step:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
And I wait 4 seconds
Then I should be on "/path-to-page"
Then my scenario passes in the green, all good.
Is there a way to get PhantomJS to wait for the page to load before checking the current path? I don't want to depend on arbitrary timeouts. I need a headless solution and PhantomJS seems to be pretty well supported, but if I can't do something as simple as clicking a link and verifying the page that was loaded without adding random waiting steps everywhere, I might need to re-evaluate my decision.
Try using this implicit wait in your feature context. In my experience it has helped.
/**
* #BeforeStep
*/
public function implicitlyWait($event)
{
// Set up implicit timeouts
$driver = $this->getSession()->getDriver()->getWebDriverSession();
$driver->timeouts()->implicit_wait(array("ms" => 10000));
}
I was having the same issue, and doing something like this fails because its using the state of the current url:
$this->getSession()->wait(10000, "document.readyState === 'complete'");
So my workaround for this was adding a variable to the page every time a step is done. When I link is clicked, the variable will no long exist, this will guarantee that am working with a different page.
/**
* #AfterStep
*/
public function setStepStatus()
{
$this->getSession()->evaluateScript('window.behatStepHasCompleted = true;');
}
/**
* #When /^(?:|I )wait for the page to be loaded$/
*/
public function waitForThePageToBeLoaded()
{
$this->getSession()->wait(10000, "!window.behatStepHasCompleted && document.readyState === 'complete'");
}
You can always make use of a closure function to encapsule your steps, just as mentioned in the docs. Through it, you can get your steps to run when they're ready. Let's implement a spinner function:
public function spinner($closure, $secs) {
for ($i = 0; $i <= $secs; $i++) {
try {
$closure();
return;
}
catch (Exception $e) {
if ($i == $secs) {
throw $e;
}
}
sleep(1);
}
}
What we're doing here is wait for a number of seconds for the closure function to run successfully. When the time's run out, throw an exception, for we want to know when something's not behaving correctly.
Now let's wrap your function to assert you're in the right page within the spinner:
public function iShouldBeOnPage($wantedUrl) {
$this->spinner(function() use($wantedUrl) {
$currentUrl = $this->getSession()->getCurrentUrl();
if ($currentUrl == $wantedUrl) {
return;
}
else {
throw new Exception("url is $currentUrl, not $wantedUrl");
}
}, 30);
What we're doing here is wait up to 30 seconds to be on the url we want to be after clicking the button. It will not wait for 30 secs, but for as many secs we need until current url is the url we need to be at. Applying it in your function within the *Context.php will result in it being applied in every step you call it within your Gherkin files.

WPF MessageBox in App.xaml.cs stops MainWindow initialisation so app never appears but is (apparently) running correctly

There's no error message and no indication why it is not displaying the window. The app initialises App.xaml.cs: App() {} and I can step through the App.xaml file. It gets the startup uri and then... silence. No output in the Output window and no unhandled exception and no window, I can't find where to put a breakpoint to debug as it isn't hitting the start of MainWindow.xaml.cs.
Really confused.
This was working 20m ago.
In that time all I did was add Windows.Office.Interop.Outlook reference. I removed the reference and rebuilt but still the same. Would that cause this problem? Has anyone seen this before? Google isn't helping!
EDIT :
App.xaml.cs:
public App()
{
using (var dbContext = new DBEntities())
{
if (!db.Exists())
{
try
{
db.Database.Create();
MessageBox.Show("Database created"); // this is the problem!!
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
I've added App.xaml.cs, I found that the problem was using a MessageBox to give info (this is still in development!). I'd been meaning to get rid of it and eventually did and my problem went away. This meant I could find relevent Goolge results:
MSDN query and answer for exactly my problem
I will be adding an 'loading window' in between app load and main window load eventually in which I will be able to feedback information using Bindings etc.
Fixed error by removing the MessageBox.Show(..) call. The selected answer from the MSDN URL given in the question states:
"I performed a test based on your description, the applicationi stop at the method : USER32!GetMessageW+0x33, calling USER32!NtUserGetMessage"
I assume this is what was occurring in my case, although I didn't test it.
What happens if you create a new window and set that as the StartupUri?
You also might want to create a new project and make sure that the namespaces referenced in the App.xaml in your existing app haven't somehow been inadvertently edited.

Resources