I have an app that is listening in background and when the user clicks "send" it displays a dialogue. However I need to bring my app to foreground so the user answers some questions before letting the message go. but I haven't been able to do this, this is the code in my SendListener:
SendListener sl = new SendListener(){
public boolean sendMessage(Message msg){
Dialog myDialog = new Dialog(Dialog.D_OK,
"message from within SendListener",
Dialog.OK,Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
Dialog.GLOBAL_STATUS)
{
//Override inHolster to prevent the Dialog from being dismissed
//when a user holsters their BlackBerry. This can
//cause a deadlock situation as the Messages
//application tries to save a draft of the message
//while the SendListener is waiting for the user to
//dismiss the Dialog.
public void inHolster()
{
}
};
//Obtain the application triggering the SendListener.
Application currentApp = Application.getApplication();
//Detect if the application is a UiApplication (has a GUI).
if( currentApp instanceof UiApplication )
{
//The sendMessage method is being triggered from
//within a UiApplication.
//Display the dialog using is show method.
myDialog.show();
App.requestForeground();
}
else
{
//The sendMessage method is being triggered from
// within an application (background application).
Ui.getUiEngine().pushGlobalScreen( myDialog, 1,
UiEngine.GLOBAL_MODAL );
}
return true;
}
};
store.addSendListener(sl);
App is an object I created above:
Application App = Application.getApplication();
I have also tried to invoke the App to foreground using its processID but so far no luck.
i have managed to achieve something similar to what you're describing but the difference is, my dialogs are displayed asynchronously, which might actually be easier... so in your case..
the first i could suggest you try is get the event lock before pushing the screen, ala:
synchronized(Application.getEventLock()){
final UiEngine ui = Ui.getUiEngine();
ui.pushGlobalScreen(theScreen, 1, UiEngine.GLOBAL_MODAL);
}
I would also just create a custom class of type MainScreen and push that instead of plain Dialog.
There, that's better (now with code formatting).
public class MYSendListener implements SendListener {
private UiApplication _myApp;
public MySendListener(UiApplication myApp) {
_myApp = myApp;
}
public boolean sendMessage(Message m) {
...
_myApp.requestForeground();
}
}
Cache your app instance inside your send listener when you construct it, and use that when sendMessage is fired.
Application.getApplication() only gets you the app of the calling thread.
Related
I am using a ListField Control to display data returned from xml webservice. I want to refresh the ListField or the screen every minute to update the ListField with new records or data.
I tried using the code below but it is not working properly (It is hanging).
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
ResponseHandler handler = new ResponseHandler();
ListField listUsers = new ListField(handler.getItem().size());
public MyScreen() {
setTitle("yQAforum");
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
listUsers.setCallback(this);
listUsers.setEmptyString("No Users found", 0);
add(listUsers);
}
You are attempting to fetch data from your webservice on the UI thread. That's almost always the wrong thing to do.
The UI thread (also known as the main thread) is responsible for drawing the UI, and tracking user actions, like touches, or navigation via a trackpad/trackball. If the UI thread is blocked waiting for a remote web server to respond, it cannot service the UI.
There's a couple changes you should make:
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
should be changed to
public MyApp() {
// Push a screen onto the UI stack for rendering.
pushScreen(new MyScreen());
}
The MyApp() constructor will already be called on the UI thread, so there is no need to use invokeLater() to perform the pushScreen() call on the UI thread. It already will be called on the UI thread, if run from within the MyApp constructor. Also, the 5000 msec delay isn't really helpful. This will just delay the startup of your app by 5 seconds, which users will hate.
If you are trying to implement a splash screen, or something similar, when the app starts up, please search stack overflow for "BlackBerry splash screen", and I'm sure you'll find results.
Now, once your MyScreen class is created, you should take care not to fetch web service results from the UI thread. The MyScreen constructor will be run on the UI thread. If you want, you can initiate a web service request on a background thread, once the screen is shown. One way to do that is to use onUiEngineAttached():
protected void onUiEngineAttached(boolean attached) {
if (attached) {
// TODO: you might want to show some sort of animated
// progress UI here, so the user knows you are fetching data
Timer timer = new Timer();
// schedule the web service task to run every minute
timer.schedule(new WebServiceTask(), 0, 60*1000);
}
}
public MyScreen() {
setTitle("yQAforum");
listUsers.setEmptyString("No Users found", 0);
listUsers.setCallback(this);
add(listUsers);
}
private class WebServiceTask extends TimerTask {
public void run() {
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
// now, update the UI back on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// TODO: record the currently selected, or focused, row
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
// Note: if you don't see the list content update, you might need to call
// listUsers.invalidate();
// here to force a refresh. I can't remember if calling setSize() is enough.
// TODO: set the previously selected, or focused, row
}
});
}
}
You'll need to add some error handling, in case the web service doesn't respond, or takes longer than a minute (you wouldn't want to be making a new request, if the last one hadn't finished).
But, this should get you started.
Note: once you fix the problem with running network code on the UI thread, you may still find that your code doesn't work. There could be problems fetching the web service data. You'll have to debug that. I am only showing you one problem with the code posted. If you still have problems with the web service fetch, post another question (with the UI thread problem fixed). Thanks.
Hello I am trying to create a please wait screen.This screen will appear when my program requests data from web service and will hide when the process is finished.Also I want to add a time out if request process lasts longer than 90 seconds.
can anyone help or show me a guiding example about that matter.
public static void showBusyDialog() {
try
{
if (busyDialog == null) {
busyDialog = new Dialog("Please Wait", null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS));
busyDialog.setEscapeEnabled(false);
}
synchronized (Application.getEventLock()) {
busyDialog.show();
}
}
catch(Exception e)
{
}
}
and my hiding code is
public static void hideBusyDialog() {
try
{
if (busyDialog == null) {
// busyDialog = new Dialog("Please wait...", null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS));
busyDialog.setEscapeEnabled(false);
}
synchronized (Application.getEventLock()) {
busyDialog.close();
}
}catch(Exception e)
{
}
}
Many BlackBerry® smartphone applications need to wait for some network activity (or another blocking operation, which must process in the background), while still holding up the User Interface (UI) and displaying a progress indicator.
You can follow through this links
Links
Sample "Please Wait" screen - part 1
Sample "Please Wait" screen - part 2
Sample "Please Wait" screen - part 4
you can download simple examples for Please wait screen
PleaseWait1.zip 25 KB
PleaseWait2.zip 25 KB
PleaseWait3.zip 25 KB
Note :in case above Links not working then just follow following contents
There seem to be two common issues when programming this:
1) As applications are not allowed to block the Event Thread, how do they get the UI processing to wait?
2)How can the background Thread update the UI?
This article is intended to help with these issues and provide a fully functioning "Please Wait" sample Popup Screen. However, as there is quite a lot to explain, in this first article, we will just create a popup screen that will show itself, hold up the UI, and then remove itself once the background processing has finished. This does not give us any progress indication, nor does it let the user cancel the wait. These points will be covered in a followup article. But the code supplied with this article will be useful anyway, especially when the duration of the background processing is not known and the user may not cancel the processing.
First, we start with the background processing we need to run. While this could be anything, typically this will be network processing, like the following:
httpConn = (HttpConnection)Connector.open(_url + ";deviceside=true");
responseCode = httpConn.getResponseCode();
responseMessage = "Response Code: " + Integer.toString(responseCode);
To initiate this network processing, we have a MainScreen that contains
1) A BasicEditField that allows the entry of a URL
2) A RichTextField that should display the response code (or error message). Here are the important parts of that screen:
BasicEditField _requestedURLField = new BasicEditField("http://", "www.blackberry.com", 255, BasicEditField.FILTER_URL);
RichTextField _responseField = new RichTextField("<response code>", RichTextField.NON_FOCUSABLE);
We would like the MainScreen to be updated with the result. As noted above, background processing can't directly update the UI; UI updating code must be on the Event Thread. There are several ways to get a background process onto the Event Thread, see the related article for more. In this case, we will use the following code:
// Make things final so we can use them in the inner class
final String textString = responseMessage;
final RichTextField rtf = _resultField;
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
rtf.setText(textString);
}
});
Now we must define the PleaseWaitPopupScreen to be displayed while waiting.
To give the user something to look at while they are waiting, we have an animated .gif, which is diplayed using the code in the AnimatedGIFField (see related link). And, so the user knows what they are waiting for, the PleaseWaitPopupScreen is supplied with a String to display, as the following constructor shows:
private PleaseWaitPopupScreen(String text) {
super(new VerticalFieldManager(VerticalFieldManager.VERTICAL_SCROLL | VerticalFieldManager.VERTICAL_SCROLLBAR));
GIFEncodedImage ourAnimation = (GIFEncodedImage) GIFEncodedImage.getEncodedImageResource("cycle.agif");
_ourAnimation = new AnimatedGIFField(ourAnimation, Field.FIELD_HCENTER);
this.add(_ourAnimation);
_ourLabelField = new LabelField(text, Field.FIELD_HCENTER);
this.add(_ourLabelField);
}
PleaseWaitPopupScreen provides a method – showScreenAndWait(..) – which will create and display the Popup screen, run the Background processing, and then dismiss the Popup screen.
The final piece of the puzzle involves supplying showScreenAndWait(..) with the processing to run.
Java has the concept of a Runnable, which is an Object that contains a public void run() method that should be executed. In this case, we have the Connection code and screen update code, given above, that should be executed. So, this code is packaged up into a new Runnable Object, which is supplied to showScreenAndWait(..). And here is that method. Note how a new Thread is created and run.
public static void showScreenAndWait(final Runnable runThis, String text) {
final PleaseWaitPopupScreen thisScreen = new PleaseWaitPopupScreen(text);
Thread threadToRun = new Thread() {
public void run() {
// First, display this screen
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(thisScreen);
}
});
// Now run the code that must be executed in the Background
try {
runThis.run();
} catch (Throwable t) {
t.printStackTrace();
throw new RuntimeException("Exception detected while waiting: " + t.toString());
}
// Now dismiss this screen
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen(thisScreen);
}
});
}
};
threadToRun.start();
}
And this is the key part of the PleaseWaitPopupScreen. Note how this code will create and display a Popup screen to the user, including an animated icon, while it is running the background processing. Input from the user is blocked by the Popup screen until the processing completes. The originating screen is updated as a result of the background processing.
Download the associated .zip archive, which contains the source included in this article.
In the next article, we will extend this code to be able to handle:
a) Status updates from the Background Thread
b) "Time to go" indication
c) Being cancelled by the BlackBerry smartphone user
Just put timer after you show busy dialog.
showBusyDialog();
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
hideBusyDialog();
}
};
timer.schedule(task, 9000);
this is for time out. If the process finishes less than 90 seconds you should call
timer.cancel();
timer = null;
task = null;
I am using a popup screen to show the update status of background uploading processes. I want to cancel the uploading in between. I am trying to achieve this either by addin a button to the pop up screen or with the physical backbutton of the device. But it seems that none of the events generated are caught by the app.
Here is how I am creating a popup screen and displaying it t user
DialogFieldManager manager = new DialogFieldManager();
//DialogFieldManager manager = (DialogFieldManager)getDelegate();
statusUpdate = new LabelField("Please Wait...");
manager.addCustomField(statusUpdate);
_gaugeField = new GaugeField("", 0, 100, 0, GaugeField.PERCENT);
manager.addCustomField(_gaugeField);
cncl_Btn = new ButtonField("Cancel",ButtonField.CONSUME_CLICK | ButtonField.FIELD_HCENTER | ButtonField.NEVER_DIRTY);
manager.addCustomField(cncl_Btn);
cancelFlag = 0;
cncl_Btn.setChangeListener(new FieldChangeListener()
{
public void fieldChanged(Field field, int context) {
// Auto-generated method stub
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
cancelFlag = 1;
//onClose();//as this method exited from application
// close();//this method gave me IllegalStateException
}
});
}
});
//BackUpScreen.this.addMenuItem(_viewItem);
popup = new PopupScreen(manager);
UiApplication.getUiApplication().pushScreen(popup);
Soon afther this line I am calling the actual upload process in a thread like this
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
//.... do other stuff I wanted done...
backUpThread = Thread.currentThread();
uploadItems();
}
});
But if I press the cancel button inside the popup screen its not responding. I checked this by adding a breakpoint inside the fieldchange listener method of button.
How can I do this in blackberry?
The call to invokeLater (int the second bit of code) causes that Runnable to be executed on the event thread. If anything you do on the event thread blocks then the UI will become unresponsive as you describe. Any calls that may block must not be run on the event thread.
I am using AttachmentDownloadManager class download method to download the email attachments to the device.I am displaying a progress screen while the attachments gets downloaded to device.In the downloadCompleted() event listener method, I am trying to stop/close the progress screen but unable to do so.
Below is the code snippet:
attachmentDownloadMngr = new AttachmentDownloadManager();
attachmentDownloadMngr.download(attachmentBodyPart, null, new IGAEmailAttachmentListener(this));
Below are DownloadProgressListener event listener methods:
public void updateProgress(Object element, int current, int total)
{
synchronized(UiApplication.getEventLock())
{
Ui.getUiEngine().pushGlobalScreen(progressScreen,1,UiEngine.GLOBAL_QUEUE);
}
}
public void downloadCompleted(Object element)
{
synchronized(UiApplication.getEventLock())
{
Ui.getUiEngine().popScreen(progressScreen);
}
}
public void downloadCancelled(Object element)
{
}
progressScreen is instance of PopupScreen where I am displaying a guagefield. The progress screen does not get any events even after the attachment download is completed.
Please help me to solve this issue.
You seem to be pushing a globalscreen every time you get a callback to updateprogress() . I wouldn't do it. I would rather push the globalscreen with the gaugefield when I start the download, and then set the value of gaugefield using gaugeField.setValue(value).
the way you are doing it would mean, the event thread pushes too many screens on to the stack, and I guess it would throw a run time exception and kill your app.
I have a listfield in my app showing a list of contacts. I would like to call the selected contact when the user presses the green call button (instead of the default behaviour which launches the phone call log app).
This means there are 2 issues:
1) can I intercept the green call button?
2) how can I make the call from the app?
Before answering the question, it is assumed that you are keeping track of the currently selected item in the list, and you have a way of finding the related phone number.
1) Intercept the call button
You need to implement the keyDown(int, int) method in a Manager or Screen, catch the correct keycode, and return true:
protected boolean keyDown(int keycode, int time)
{
// check for the green phone button
if (keycode == 1114112)
{
/*
* Place your custom calling code here.
*/
return true; // indicates that this method has consumed the keypress
}
else
{
return super.keyDown(keycode, time);
}
}
(based on answer given at http://supportforums.blackberry.com/t5/Java-Development/Can-Over-ride-Call-Button-using-api-Issue-Shows-Context-Menu-on/m-p/252554/highlight/true#M41073)
2) Make a phone call
You need to Invoke() the phone app, passing it the phone number you wish to call:
PhoneArguments callArgs = new PhoneArguments(
PhoneArguments.ARG_CALL, "+27 83 111 1234");
Invoke.invokeApplication(Invoke.APP_TYPE_PHONE, callArgs);
So combining gives this code:
protected boolean keyDown(int keycode, int time)
{
// check for the green phone button
if (keycode == 1114112)
{
// get phone number - you must write this yourself
String number = selectedContact.getNumber(); // assume some method here depending on your solution
// make the call
PhoneArguments callArgs = new PhoneArguments(
PhoneArguments.ARG_CALL, number);
Invoke.invokeApplication(Invoke.APP_TYPE_PHONE, callArgs);
// indicate that the key has been processed
return true;
}
else
{
return super.keyDown(keycode, time);
}
}
From the Blackberry documentation:
net.rim.blackberry.api.phone
public final class Phone extends
Object
This class provides the following:
* Advanced utilities for interaction with the Phone
application. You can use the methods
in this class for finer manipulation
of the Phone application. For example,
injecting DTMF tones into active
calls.
* Access multiple lines on the device.
* Adding data to the incoming and active call screens, if supported.
Multi-line examples
Example A: Switching a line
Create a class that extends MultiLineListener.
public class MultiLineAction extends MultiLineListener
Register the class as a PhoneListener.
Phone.addPhoneListener(this);
Implement the MultiLineListener callbacks so that the app can be
notified of switching results.
public void setPreferredLineFailure(int lineId)
{
_screen.popupMessage("Switching failed");
}
public void setPreferredLineSuccess(int lineId)
{
_screen.popupMessage("Switching to " + Phone.getLineNumber(lineId) + "
completed" );
}
Invoke Phone.setPreferredLine().
Phone.setPreferredLine( Phone.getLineIds()[0]);
Example B: Initiate an outgoing call
Invoke Phone.initiateCall.
Phone.initiateCall(Phone.getLineIds()[0],
"5195550123");
Deregister the class from the phone listener before the application
is closed.
Phone.removePhoneListener(this);
Category:
Signed: This element is only accessible by signed applications. If
you intend to use this element, please
visit
http://www.blackberry.com/go/codesigning
to obtain a set of code signing keys.
Code signing is only required for
applications running on BlackBerry
smartphones; development on BlackBerry
Smartphone Simulators can occur
without code signing. Since:
BlackBerry API 4.0.0
http://www.blackberry.com/developers/docs/6.0.0api/