Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Web and WebWorks Development

Reply
Developer
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
My Carrier: alfa Lebanon
Accepted Solution

HTML5 App - Show Pop-Up Window when message in background

Hello,

 

I need my app to display a pop-up window to the user even if the app is in the background.

How can I do this if my app is built using html5 and javascripts?

 

Thank you for any help

Wadi
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: HTML5 App - Show Pop-Up Window when message in background

Hello Wadi,

 

Unfortunately the standard alert approach does not work if your app is in the background; no alert is displayed upon execution of that code, not even after returning to your application following an event that should have triggered an alert.

 

For Smartphones, I approach that comes to mind would be a JavaScript extension that trigger some Java code, displaying a Dialog to the user.

 

JavaScript Extensions:

https://bdsc.webapps.blackberry.com/html5/documentation/ww_developing/using_javascript_extensions_18...

 

Displaying a Dialog in Java:

http://supportforums.blackberry.com/t5/Java-Development/Alert-a-BlackBerry-smartphone-user-from-a-Ba...

 

Erik Oros

BlackBerry Development Advisor


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
Developer
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
My Carrier: alfa Lebanon

Re: HTML5 App - Show Pop-Up Window when message in background

Can you please take a look at these classes that make my javascript Extension for the Popup:

 

PopupExtension.java

package samplecode;
import org.w3c.dom.Document;
import net.rim.device.api.browser.field2.BrowserField;
import net.rim.device.api.script.ScriptEngine;
import net.rim.device.api.web.WidgetConfig;
import net.rim.device.api.web.WidgetExtension;

   public final class AlertExtension implements WidgetExtension {
      public String[] getFeatureList() {
      String[] result = new String[1];
      result[0] = "sample.alert";
      return result;
   }

   public void loadFeature(String feature, String version,
Document doc, ScriptEngine scriptEngine) throws Exception {
      if (feature == "sample.alert") {
         scriptEngine.addExtension("sample.alert", new AlertNamespace());
      }
   }

   public void register(WidgetConfig arg0, BrowserField arg1) {
   // TODO Auto-generated method stub
   }

   public void unloadFeatures(Document arg0) {
   // TODO Auto-generated method stub
   }
}

 PopupNamespace.java:

package samplecode;
import net.rim.device.api.script.Scriptable;
import net.rim.device.api.system.UiApplication;

public final class PopupNamespace extends Scriptable {
   private PopupFunction callPopup;

   public PopupNamespace() {
      this.callPopup = new PopupFunction();
   }
}

 PopupFunction.java

package samplecode;
import net.rim.device.api.script.ScriptableFunction;
import net.rim.device.api.system.UiApplication;

public final class PopupFunction extends ScriptableFunction {
   public Object invoke(Object obj, Object[] args) throws Exception
   {
		synchronized(
		Application.getEventLock()){
				UiEngine ui = Ui.getUiEngine();
				Screen screen = new Dialog(Dialog.D_OK, "Look out!!!",
					Dialog.OK,
					Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
						Manager.VERTICAL_SCROLL);
				ui.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_QUEUE);
					}
	}
}

 

Now In my javascript:  sample.popup.FUNCTION();

What am I supposted to call instead of FUNCTION?

 

Thank you so much for your help. I really appreciate it Smiley Happy

 

Wadi
Highlighted
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: HTML5 App - Show Pop-Up Window when message in background

Hello Wadi,

 

This turned out to be a bit of a monster post. If you have any question at any stage of the post, please do not hesitate to ask. Let's dive in.

 

There are a few issues that I'm seeing with the code you provided.

 

PopupExtension.java


  • Creates a new AlertNamespace Object, yet your Class is called PopupNamespace.

PopupNamespace.java


  • getField is not implemented.\

PopupFunction.java


  • A lot of import statements are missing.

 

I'll show you a comparison of my files where I managed to get the Dialog displayed from within my WebWorks application; regardless of whether the application is in the foreground or background.

 

For reference, the creation of my java files is based on the code samples available here:

https://bdsc.webapps.blackberry.com/html5/documentation/ww_developing/using_javascript_extensions_18...

 

To start, I have SandboxExtension.java. This is the equivalent of your PopupExtension.java.

 

package sandbox.extension; 

import net.rim.device.api.browser.field2.BrowserField;
import net.rim.device.api.script.ScriptEngine;
import net.rim.device.api.web.WidgetConfig;
import net.rim.device.api.web.WidgetExtension;
import org.w3c.dom.Document;

public final class SandboxExtension implements WidgetExtension {
    String _widgetNameForFutureUse;
    BrowserField _browserFieldForFutureUse;
  
    public String[] getFeatureList() {
        String[] result = new String[1];
        result[0] = "sandbox.popup";
        return result;
    }

    public void loadFeature(String feature, String version, Document doc, ScriptEngine scriptEngine) throws Exception {
        if (feature.equals("sandbox.popup")) {
            scriptEngine.addExtension("sandbox.popup", new SandboxScriptable());
        }
    }

    public void register(WidgetConfig widgetConfig, BrowserField browserField) {
        _widgetNameForFutureUse = widgetConfig.getName();
        _browserFieldForFutureUse = browserField;
    }

    public void unloadFeatures(Document doc) {
    }
}

 

 Key Differences


  • I updated my package to sandbox.extension to ensure it is unique (less chance it was previously used.)
  • In getFeatureList, I and using the feature sandbox.popup; this was purely a personal choice that I made when implementing the sample. There is no real functional difference.
  • Subsequently to the first point, I also reference sandbox.popup in my remaining code; specifically within loadFeature.
  • My register method sets the two corresponding member variables.
  • I create a new SandboxScriptable Object as opposed to your AlertNameSpace Object.

 

The next file is SandboxScriptable.java. This is the equivalent of your PopupNamespace.java file. Note that This Class must refer to the Object that is created in the above file. In my case I created a SandboxScriptable Object, so I am now implementing SandboxScriptable.java to define that Object.

 

package sandbox.extension;

import net.rim.device.api.script.Scriptable;

public final class SandboxScriptable extends Scriptable {

    private SandboxPopup _sandbox;

    public SandboxScriptable() {
        _sandbox = new SandboxPopup();
    }

    public Object getField(String name) throws Exception {
        if(name.equals("doPopup")) {
            return this._sandbox;
        }
        return super.getField(name);
    }
}

 

 Key Differences


  • Slight naming changes to accomodate my variable names.
  • The getField function is (and must) be implemented. Basically, when a method is being called, I check to see whether it is the doPopup method. If so, I return a SandboxPopup Object. This would be equivalent to your PopupFunction Class. If the user is not invoking the doPopup method, I simply pass back the default behaviour via the super Object.

 

The final Class is SandboxPopup.java. This is the equivalent of your PopupFunction.java. Above, we create and return a SandboxPopup Object, so in this file we are actually implementing what that Object actually is.

 

package sandbox.extension;

import net.rim.device.api.script.ScriptableFunction;
import net.rim.device.api.system.Application;
import net.rim.device.api.ui.UiEngine;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Manager;

public final class SandboxPopup extends ScriptableFunction {
    public Object invoke(Object obj, Object[] args) throws Exception {
		synchronized(Application.getEventLock()) {
			UiEngine ui = Ui.getUiEngine();
			Screen screen = new Dialog(Dialog.D_OK, "Hello World!", Dialog.OK, Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION), Manager.VERTICAL_SCROLL);
			ui.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_QUEUE);
		}
        return "UNDEFINED";
    }
}

 

 Key Differences

 

  • I have added all the import statements for the various RIM Classes being used.
  • I am returning a default "UNDEFINED" String regardless of success.

 

And that's the gist of the java files. Basically, it is a chain of three classes; the first references the second, and the second references the third. In your sample, that chain is slightly broken, however can be fixed fairly quickly based on the notes above.

 

The next part that must be done is to associate your Javascript Extension with WebWorks. This can be done in one of two ways.

 

  • Package your extension with your application. Described in the Javascript Extension guide linked above.
  • Integrate your extension with your WebWorks SDK.

I opted for the latter as I find that approach a little more straightforward. The first thing we need to do is copy our java files into the extension folder. The root extension folder I was using is as follows:

 

C:\Program Files\Research In Motion\BlackBerry WebWorks SDK 2.3.0.9\ext\

 

Within this folder, I created a sandbox.extension sub-folder to house my extension:

 

C:\Program Files\Research In Motion\BlackBerry WebWorks SDK 2.3.0.9\ext\sandbox.extension

 

I then copied the src folder housing my java files to get the following file structure:

 

untitled2.PNG

 

Note that the src/sandbox/extension path is not a coincidence because sandbox/extension is the folder structure as dictated by the package I used in my java files. Specifically:

 

package sandbox.extension;

 

The final thing that is missing is a library.xml file. I used the library.xml files available on the WebWorks Community API Github page as a starting point and made some modifications to get the following.

 

<library isWhitelist="true">
	<extension id="sandbox.extension">
		<entryClass>sandbox.extension.SandboxExtension</entryClass>
	</extension>
	<platforms>
		<platform value="JAVA">
			<target version="default" config="JAVA" />
		</platform>
	</platforms>
	<configurations>
		<configuration name="JAVA" version="1.0" >
			<src type="text/java" path="src" comment="Sample" />
		</configuration>
	</configurations>
	<features>
		<feature id="sandbox.popup" version="1.0.0" />
	</features>
</library>

 

 Key Notes

 

  • The <entryClass> is defined to point at the Class that implements WidgetExtension. In that chain of three java files, this would be the first file.
  • Under <configurations>, I set path="src" since the actual package begins in the src subfolder.
  • Under <features> I defined the id to be sandbox.popup.

This file was created under the sandbox.extension root folder, specifically:

 

C:\Program Files\Research In Motion\BlackBerry WebWorks SDK 2.3.0.9\ext\sandbox.extension

 

And that is it for configuring the SDK. Now, when I package an application that leverages this extension, I do not need to include anything extra in my actual application because this functionality is now integrated directly with my SDK. To actually use this functionality, I need to:

 

  • Include the feature in my config.xml file.
  • Invoke the function within my Javascript.

My config.xml file looks like as follows.

 

<?xml version="1.0" encoding="utf-8"?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:rim="http://www.blackberry.com/ns/widgets" version="1.0.0">
	<name>Sandbox</name>
	<author>Oros</author>
	<content src="index.html"/>
	
	<feature id="sandbox.popup" required="true" version="1.0.0"/>
</widget>

Very basic. The <content> element indicates that index.html will be our main entry point. The important part here is that I included the <feature> element with id="sandbox.popup". You will note that this is the same id that we defined in library.xml.

 

Finally, here is a small sample application that gives the user a button. Once that button is clicked, a timer is invoked for 5 seconds. At the end of those 5 seconds, the extension (and in turn a popup Dialog) is invoked.

 

<!DOCTYPE html>
<html>
	<head>
	</head>
	<body>
		<button type="button" onclick="fire()">Go Button Go!</button>
		
		<script type="text/javascript">
			function invokeExtension() {
				sandbox.popup.doPopup();
			}
			
			function fire() {
				setTimeout(invokeExtension, 5000);
			}
		</script>
	</body>
</html>

As you can see, we add a <button> to our page that, when clicked, will trigger the fire function. The fire function calls setTimeout with a founter of 5000 milliseconds.

 

The reason for this is to give you the option of staying within the application, or minimizing the application with the red, end-call button. Regardless of whether you are in the application, or the application is minimized, after 5000 milliseconds, the invokeExtension function is called.

 

Within invokeExtension, you can see us calling sandbox.popup.doPopup. sandbox.popup is the Object we've defined in library.xml and subsequenty implemented within our java files. doPopup is the function that we defined to be handled within the java files.

 

Again, if you have any questions about the above, please do let me know.

 

Erik Oros

BlackBerry Development Advisor


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
Developer
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
My Carrier: alfa Lebanon

Re: HTML5 App - Show Pop-Up Window when message in background

Thank you so much Erik. I can't tell you much this helped me, this is so much better than any documentation I was able to find.
I'm sure this will help a lot of users who read this.

Just one last question, if I want to know if the user pressed "ok" or "cancel", do I just 'return' the value and directly get it in the javascript?

Again, thank you! I really appreciate your walkthrough and detailed process Smiley Happy
Wadi
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: HTML5 App - Show Pop-Up Window when message in background

Hello Wadi,

 

That's right. Whatever you return will be converted to the corresponding type in JavaScript. For instance, in my method I am calling the following, regardless of any action taken:

return "UNDEFINED";

 

However, if I were to create a blacking/modal popup instead, and then retrieve the user's choice, then I could return any value I like.

 

Currently, I am calling:

sandbox.popup.doPopup();

 

However if I were to modify that to:

alert(sandbox.popup.doPopup();

 

Then I would be alerted with the String "UNDEFINED". Again, this is because that is the only return that I have defined my my Java function.

 

With a few modifications you can return an actually meaningful value and use that in your JavaScript as required.

 

Erik Oros

BlackBerry Development Advisor


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
Developer
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
My Carrier: alfa Lebanon

Re: HTML5 App - Show Pop-Up Window when message in background

Sorry to bother you again with this, but I figured since it's on the same topic and anyone else checking this thread might have this problem as well. Anyways, this dialog method is working great on OS6 and OS7. However on OS5, i'm getting this error when the popup method is called:

java.lang.RunTimeException: pushGlobalScreen(modal) called bya non-event thread

 

This is my SandboxPopup.java right now:

public final class SandboxPopup extends ScriptableFunction {
    public Object invoke(Object obj, Object[] args) throws Exception {
    	String msg = ((String)args[0]);
		synchronized(Application.getEventLock()) {
			UiEngine ui = Ui.getUiEngine();
			Screen screen = new Dialog(Dialog.D_YES_NO, msg, Dialog.NO, Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION), Manager.VERTICAL_SCROLL);
			ui.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_MODAL);
			
			int response = ((Dialog)screen).getSelectedValue();
			if (response == Dialog.YES) {
				return "yes";
			}
			else
				return "no";
		}
    }
}

 I remember facing something like this when I was developing in Java. The solution then was to determine if the screen being pushed was from the background or not, like this code below:

 

synchronized(Application.getEventLock()){
	    	final Dialog d = new Dialog(Dialog.D_YES_NO, msg,
	   	Dialog.NO, Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION), Manager.VERTICAL_SCROLL);
	    	if ( Application.isEventDispatchThread() ) {
		    	// We have the Event Thread, can just show the Dialog
		    	UiApplication.getUiApplication().pushModalScreen(d);
	    	} else {
		    	// running in background
	    		UiApplication.getUiApplication().invokeLater(new Runnable() {
		    	public void run() {
			    	UiApplication.getUiApplication().pushGlobalScreen(d, 1, UiEngine.GLOBAL_MODAL);
			    	if (d.getSelectedValue() == Dialog.YES )
			    	{
						isOn = false;
						lstOnOff.setSelectedIndex(1);
				}
		    		}
		    	});
	    	}
	    
	    	if (d.getSelectedValue() == Dialog.YES )
	    	{
				isOn = false;
				lstOnOff.setSelectedIndex(1);
		} 

The problem now is how to return to the Javascript when the code goes into the invokeLater? I can't manipulate the javascipt needed in the run() part. I'm hoping there is an easy fix that I'm missing somewhere, please note again that this problem only occurs with OS 5.

 

Thank you up front Smiley Happy

Wadi
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: HTML5 App - Show Pop-Up Window when message in background

Hello Wadi,

 

My personal recommendation would be the continued use the GLOBAL_QUEUE option instead of GLOBAL_MODAL. From there, you can leverage DialogClosedListener to wait for the user to make their choice.

 

Of course, this brings about a similar problem where we are now receiving the input in a function that is not directly returning a value.

 

It is possible to sequence our Java function properly through the use of a lock Object in conjunction with a wait/notify implementation. However, we can also leverage a Javascript callback method, which would be my recommendation here; both for simplicity, and that generally good feeling you get when you don't have to hack stuff together.

 

To accomplish this, I've modified the way I am invoking the extension in my JavaScript:

 

<!DOCTYPE html>
<html>
	<head>
	</head>
	<body>
		<button type="button" onclick="invokeExtension();">Callback!</button>
		
		<script type="text/javascript">
			function invokeCallback(choice) {
				alert(choice);
			}

			function invokeExtension() {
				try {
					sandbox.popup.doPopup(invokeCallback);
				} catch (err) {
					alert(err);
				}
			}
		</script>
	</body>
</html>

 

As you can see, we have one button that calls invokeExtension. We then call doPopup in the same fashion, however now we are passing in an argument; specifically the callback function that we want invoked.

 

When that callback function is invoked, it is expected to be passed one argument (namely the choice that the user made) and that value will be displayed.

 

So let's look at the Java link between our Javascript function and its callback. The only file that we actually need to modify here is SandboxPopup.java; the Java implementation of our extension.

 

package sandbox.extension;

import net.rim.device.api.script.ScriptableFunction;
import net.rim.device.api.ui.UiEngine;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.DialogClosedListener;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Manager;

public final class SandboxPopup extends ScriptableFunction {
	private static ScriptableFunction _callback = null;
	
    public Object invoke(Object obj, Object[] args) throws Exception {
    	try {
			_callback = (ScriptableFunction)args[0];
			
			Dialog dialog = new Dialog(Dialog.D_YES_NO, "Hello World?", Dialog.YES, Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION), Manager.VERTICAL_SCROLL);
			dialog.setDialogClosedListener(new DialogClosedListener() {
				public void dialogClosed(Dialog dialog, int choice) {
					try {
						_callback.invoke(null, new Object[] {new Integer(choice)});
					} catch(Exception ex) {}
				}
			});
			
			synchronized(Application.getEventLock()) {
				Ui.getUiEngine().pushGlobalScreen(dialog, 1, UiEngine.GLOBAL_QUEUE);
			}
		} catch(Exception ex) {
			return ex.toString();
		}
		return "Success.";
    }
}

 

After the imports, the first thing we're doing is converting args[0] into a ScriptableFunction and storing it in our private static variable _callback. Note that args[0] corresponds to the first argument passed in our Javascript call:

 

sandbox.popup.doPopup(invokeCallback); //invokeCallback becomes args[0]

 

From there, we set a DialogClosedListener (which I will talk about in a second), and then the rest is the same. We synchronize on Application.getEventLock() and I then return an arbitrary String. Note that I've added a try/catch block around everything and return the error now; this is simply for debugging purposes.

 

So, looking at our DialogClosedListener, we really only have one line (wrapped in its own try/catch block.)

 

We take the _callback Object that we initialized at the very start, and call its invoke method. You can find detailed information about the arguments we pass here:

http://www.blackberry.com/developers/docs/7.1.0api/net/rim/device/api/script/ScriptableFunction.html

 

However the key part is that we are creating an Object array which will be converted to a parameter list. Specifically, in our callback function:

 

			function invokeCallback(choice) {
				alert(choice);
			}

choice will correspond to new Integer(choice) of the Object array. This conversion between Java and Javascript Objects happens automatically for standard types.

 

Erik Oros

BlackBerry Development Advisor


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
Developer
Posts: 165
Registered: ‎10-04-2010
My Device: P'9982 & Z10
My Carrier: alfa Lebanon

Re: HTML5 App - Show Pop-Up Window when message in background

Again, your reply was extremely helpful and direct Erik.
It works perfectly, on all OS versions (5+)

Thank you Smiley Happy
Wadi
New Developer
Posts: 32
Registered: ‎05-05-2014
My Device: 9780
My Carrier: Idea

Re: HTML5 App - Show Pop-Up Window when message in background

where to pu library.xml i getting error while building the project as " feature cannot be found in any extension(sandbox.popup)"