What I want to do is have the a map open with the click of a buttonfield with two Criterias, the user must either specify the location and then the image must be added to the location otherwise the Image must be added to the users current location.
The problem I am having is adding both criterias into an if statement in a thread / new thread or even in a FieldChangeListener.
The error I keep getting is:
Error in location :javax.microedition.location.LocationException:
getLocation() method cannot be cal[0.0] led from event thread [0.0]
Error in location :getLocation() method cannot be called from event
thread
My code:
FieldChangeListener Listener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
ButtonField buttonClicked = (ButtonField) field;
if ((buttonClicked.getLabel()).equals("Push")) {
CustomMapField mMapField;
Coordinates mCoordinates;
BlackBerryCriteria blackBerryCriteria = null;
BlackBerryLocation blackBerryLocation = null;
BlackBerryLocationProvider blackBerryLocationProvider = null;
double Doublelat = 0.0;
double Doublelng = 0.0;
blackBerryCriteria = new BlackBerryCriteria();
if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_CELLSITE)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_CELLSITE);
}else if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_ASSIST)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_ASSIST);
}else if(GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_AUTONOMOUS)){
blackBerryCriteria.setMode(GPSInfo.GPS_MODE_AUTONOMOUS);
}else{
blackBerryCriteria.setCostAllowed(true);
blackBerryCriteria.setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
} try {
blackBerryLocationProvider = (BlackBerryLocationProvider) BlackBerryLocationProvider.getInstance(blackBerryCriteria);
blackBerryLocation = (BlackBerryLocation) blackBerryLocationProvider.getLocation(60);
QualifiedCoordinates qualifiedCoordinates = blackBerryLocation.getQualifiedCoordinates();
Doublelat = qualifiedCoordinates.getLatitude();
Doublelng = qualifiedCoordinates.getLongitude();
mCoordinates = new Coordinates(Doublelat, Doublelng, 0);
mMapField = new CustomMapField();
mMapField.mIcon = Bitmap.getBitmapResource("coin_silver.png");
mMapField.moveTo(mCoordinates);
mMapField.setZoom(1);
add(mMapField);
}catch(Exception e){
System.out.println("Debug 5");
System.out.println("Error in location :"+e.toString());
System.out.println("Error in location :"+e.getMessage());
}
}
}
};
public class CustomMapField extends MapField {
Bitmap mIcon;
XYRect mDest;
public void moveTo(Coordinates coordinates) {
super.moveTo(coordinates);
mDest = null;
}
protected void paint(Graphics graphics) {
super.paint(graphics);
if (null != mIcon) {
if (null == mDest) {
XYPoint fieldOut = new XYPoint();
convertWorldToField(getCoordinates(), fieldOut);
int imgW = mIcon.getWidth();
int imgH = mIcon.getHeight();
mDest = new XYRect(fieldOut.x - imgW / 2,
fieldOut.y - imgH, imgW, imgH);
}
graphics.drawBitmap(mDest, mIcon, 0, 0);
}
}
}
The error Is with the following line add(mMapField);
Doublelat = qualifiedCoordinates.getLatitude();
Doublelng = qualifiedCoordinates.getLongitude();
mCoordinates = new Coordinates(Doublelat, Doublelng, 0);
mMapField = new CustomMapField();
mMapField.mIcon=Bitmap.getBitmapResource("coin_silver.png");
mMapField.moveTo(mCoordinates);
mMapField.setZoom(1);
add(mMapField);
/*MapView mapView = new MapView();
mapView.setLatitude(finalintlat);
mapView.setLongitude(finalintlng);
mapView.setZoom(10);
MapsArguments mapsArgs = new MapsArguments(mapView);
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, mapsArgs);
Please advise me more in detail how to do so, and please give an example; I can't understand how as "mMapField" is a custom MapField and "mapView" is a class Mapview (please see my code snippet above).
Obtaining a location is a time-consuming task, it can take as much as 1 minute even with good satellite visibility, although newer berries have improved a lot the time-to-first-fix (TTFF).
Time consuming tasks, like opening connections, or obtaining a fix, should not be performed in the event thread, because this thread has to respond to user events, and if you hog it, then the GUI frozens. And everything running inside fieldChanged runs in the event thread. So it is a good thing RIM implemented a thread detection in its new BlackBerryLocationProvider and throws exceptions, now you are aware of the bad design and can take corrective measures.
You have several options to get a fix asynchronously:
Use LocationListener.
Spawn a new thread.
Preemtively obtain a fix long before you need it (or at regular intervals), then you'll have it quickly available when the button is pressed, (either retrieving it from somewhere you previously saved it or calling LocationProvider.getLastKnownLocation).
You should use Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments(mMapField)); in place of add(mMapField);
Related
I am working on a BlackBerry Application that is supposed to update the location at fixed intervals. The interval value can be selected/changed from a slider. It varies between 1 minute, 2 minutes, 5 minutes, 30 minutes etc. On the very first load (Start App), location interval is 30 seconds. After this, I store the slider value in a persistent store and location is updated accordingly with the set interval. Background thread running to update location is as follows:
private boolean startLocationUpdate()
{
boolean retval = false;
try
{
LocationProvider locationProvider = LocationProvider.getInstance(null);
if ( locationProvider == null )
{
Runnable showGpsUnsupportedDialog = new Runnable()
{
public void run()
{
Dialog.alert("GPS is not supported on this platform, exiting...");
//System.exit( 1 );
}
};
UiApplication.getUiApplication().invokeAndWait( showGpsUnsupportedDialog ); // Ask event-dispatcher thread to display dialog ASAP.
}
else
{
locationProvider.setLocationListener(new LocationListenerImpl(), interval, -1, -1);
retval = true;
}
}
catch (LocationException le)
{
System.err.println("Failed to instantiate the LocationProvider object, exiting...");
System.err.println(le);
System.exit(0);
}
return retval;
}
private class LocationListenerImpl implements LocationListener
{
public void locationUpdated(LocationProvider provider, Location location)
{
if(location.isValid())
{
double longitude = location.getQualifiedCoordinates().getLongitude();
double latitude = location.getQualifiedCoordinates().getLatitude();
updateLocationScreen(latitude, longitude);
}
}
public void providerStateChanged(LocationProvider provider, int newState)
{
}
}
private void updateLocationScreen(final double latitude, final double longitude)
{
UiApplication.getUiApplication().invokeAndWait(new Runnable()
{
public void run()
{
double lat = latitude;
double longi = longitude;
lblLatitude.setText(Double.toString(lat));
spacing.setText(", ");
lblLongitude.setText(Double.toString(longi));
}
});
}
Along with this, there is a "Refresh" button available that will start acquiring a location update immediately once clicked. This button calls a method is another class to acquire the location. The method is as follows:
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
double heading = 0;
double velocity = 0;
try {
Location myLocation = myLocationProvider.getLocation(6000);
if(myLocation.isValid())
{
double longitude = myLocation.getQualifiedCoordinates().getLongitude();
double latitude = myLocation.getQualifiedCoordinates().getLatitude();
}
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
//Dialog.alert("Location Updated");
}
});
setLocation(myLocation.getQualifiedCoordinates(),velocity,heading);
} catch ( InterruptedException iex ) {
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
Problems I am facing:
1) Interval value not changing. I am implementing the change by picking the value from the persistent store as:
if (PersistentStoreHelper.persistentHashtable.containsKey("gpsInterval"))
{
String intervalValue=((String) PersistentStoreHelper.persistentHashtable.get("gpsInterval"));
MyScreen.interval=Integer.parseInt(intervalValue);
}
This is never empty as navigation to this page inserts a value of 30 minutes to it.
2) Once the "Refresh" button is clicked, the background thread seems to be cancelled. It no longer runs at any interval value.
I read that there is only one instance of the location provider created and with "Refresh" it is cancelled after acquiring the location and thus the background thread stops. Is this true? If yes, how can I achieve my desired result.
EDIT: The gpsInterval value is read as follows:
if (PersistentStoreHelper.persistentHashtable.containsKey("gpsInterval"))
{
String intervalValue=((String)PersistentStoreHelper.persistentHashtable.get("gpsInterval"));
interval=Integer.parseInt(intervalValue);
}
else
{
interval=10;
}
Saving the Interval
So, first of all, make sure that when you let the user change the update interval, via the slider, you properly save it to the PersistentStore. The code should look something like this:
// NOTE: I would recommend persisting the slider value as an Integer, not a String,
// but, the original code used String, so that's what this uses
hashtable.put("gpsInterval", (new Integer(intervalSlider.getValue())).toString());
PersistentObject po = PersistentStore.getPersistentObject(APP_BUNDLE_ID);
po.setContents(hashtable);
po.commit();
Since you didn't post that code, I just wanted to be sure that it was being saved to the persistent store correctly.
Updating the Location Provider / Listener
The other issue, that is a problem, is that you kick off the location updates in startLocationUpdate() with this code:
locationProvider.setLocationListener(new LocationListenerImpl(), interval, -1, -1);
That uses the value of the interval variable at the instant that setLocationListener() is called. If you later update the interval variable,
String intervalValue=((String) PersistentStoreHelper.persistentHashtable.get("gpsInterval"));
MyScreen.interval=Integer.parseInt(intervalValue);
this will have no effect on the location listener. It will keep updating with the original interval value, not the new one. You would have to call setLocationListener() again, with the new value of interval. With your code, you should probably just call startLocationUpdate() again:
String intervalValue=((String) PersistentStoreHelper.persistentHashtable.get("gpsInterval"));
MyScreen.interval=Integer.parseInt(intervalValue);
startLocationUpdate();
Refresh Problem
I'm not 100% sure, but my guess would be that in your existing code that's used when the Refresh button is pressed, you are changing to a different LocationProvider with different criteria. That's probably why the first one is cancelled.
Try changing your startLocationUpdate() method to save the provider as a member variable:
/** this is the one location provider used by this class! */
private LocationProvider _locationProvider;
private boolean startLocationUpdate()
{
boolean retval = false;
try
{
_locationProvider = LocationProvider.getInstance(null);
then, in your refresh code, use the same location provider to get the current location:
double heading = 0;
double velocity = 0;
try {
Location myLocation = _locationProvider.getLocation(6000);
if(myLocation.isValid())
Note: if you really do want to setCostAllowed(false), that's fine. Do that the first time that you assign the _locationProvider member variable. And use that provider/criteria both for normal periodic location updates, and your Refresh button handler. I think the key is to use the same provider, not create a new one with different criteria.
I am trying to refresh the current location through a click of a button. The location can be acquired via GPS or Cell Tower, whichever is available. My problem is I never see the "Loading Screen". I know it appears as something appears/closes instantly while the coordinates remain zero. Can somebody help me - what I am doing wrong below?
Neither the location is updated nor the loading screen appears. Without the loading screen and by multiple clicks of the "refresh button" I do get the location. Below is my code for handling clicks on the "Refresh Button":
FieldChangeListener refreshImgListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
Thread backgroundWorker = new Thread(new Runnable() {
public void run() {
refreshCoordinates();
}
});
busyDialog.setEscapeEnabled(false);
busyDialog.show();
backgroundWorker.start();
}
};
And my refreshCoordinates() method is as below:
public void refreshCoordinates() {
do
{
getLatitude(handleeGPS.latitude);
getLongitude(handleeGPS.longitude);
} while ((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));
UiApplication.getUiApplication().invokeLater( new Runnable()
{
public void run ()
{
lblLatitude.setText(lati);
lblLongitude.setText(longi);
busyDialog.cancel();
}
} );
}
public static String getLatitude(double value)
{
lati= Double.toString(value);
return lati;
}
public static String getLongitude(double value)
{
longi= Double.toString(value);
return longi;
}
Class that returns the latitude and longitude values:
public class handleeGPS{
static GPSThread gpsThread;
public static double latitude;
public static double longitude;
public handleeGPS(){
gpsThread = new GPSThread();
gpsThread.start();
}
private static class GPSThread extends Thread{
public void run() {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
int m_bbHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs");
if(m_bbHandle>0){
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
WriteDataGoogleMaps(outputStream2, cellID, lac);
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
int code = dataInputStream2.readInt();
//Dialog.alert(code+"");
if (code == 0) {
latitude= dataInputStream2.readInt() / 1000000D;
longitude=dataInputStream2.readInt() / 1000000D;
//Dialog.alert(latitude+"-----"+longitude);
dataInputStream2.readInt();
dataInputStream2.readInt();
dataInputStream2.readUTF();
} else {
System.out.println("Error obtaining Cell Id ");
}
outputStream2.close();
inputStream2.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
} else {
try {
LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = myLocationProvider.getLocation(300);
latitude = myLocation.getQualifiedCoordinates().getLatitude();
longitude = myLocation.getQualifiedCoordinates().getLongitude();
if(latitude==0.0 && longitude==0.0){
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();
//getOutputStream();
WriteDataGoogleMaps(outputStream2, cellID, lac);
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();
//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
int code = dataInputStream2.readInt();
//Dialog.alert(code+"");
if (code == 0) {
latitude= dataInputStream2.readInt() / 1000000D;
longitude=dataInputStream2.readInt() / 1000000D;
//Dialog.alert(latitude+"-----"+longitude);
dataInputStream2.readInt();
dataInputStream2.readInt();
dataInputStream2.readUTF();
} else {
System.out.println("Error obtaining Cell Id ");
}
outputStream2.close();
inputStream2.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
catch ( InterruptedException iex ) {
return;
}
catch ( LocationException lex ) {
return;
}
} catch ( LocationException lex ) {
return;
}
}
return;
}
}
private static void WriteDataGoogleMaps(OutputStream out, int cellID, int lac)
throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.writeShort(21);
dataOutputStream.writeLong(0);
dataOutputStream.writeUTF("en");
dataOutputStream.writeUTF("Android");
dataOutputStream.writeUTF("1.0");
dataOutputStream.writeUTF("Web");
dataOutputStream.writeByte(27);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(3);
dataOutputStream.writeUTF("");
dataOutputStream.writeInt(cellID);
dataOutputStream.writeInt(lac);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.flush();
}
}
Ok, so although my original answer was valid, the new code you posted has some different problems, so I'm posting a second answer. There were enough things that didn't look right, that I just rewrote your handleeGPS class. I'll explain the major changes I made, one-by-one:
Try to use Java naming conventions. This makes it easier for us to help you. Before you posted the code to your handleeGPS class, I thought it was a variable, because lowercase names are usually used for variables, not classes.
Avoid duplicating code. The handleeGPS class had a lot of code to read through, but most of it was the code to get location from Google's web service, which you duplicated in two places. Just make a method that contains only that code, and call it twice.
I renamed your handleeGPS class to GPSHandler. I'm not sure if handlee was an error, or if that's a word in another language that you used. Anyway, the name should at least start with an uppercase letter.
Avoid lots of static variables and methods. Sometimes, there really should be only one of something. A GPS handling class is probably a good example of that, because the device only has one GPS system. But, to enforce this code construct, don't mark everything as static. Just make the class a Singleton, which involves creating only one static member variable (_instance) and one static method (getInstance()). In my code, you will access the class like this: GPSHandler gps = GPSHandler.getInstance();.
I believe the check you had for whether BB maps was installed was actually backwards. You looked up the net_rim_bb_lbs module, and if it was greater than zero (which means BB Maps is installed) then you went directly to the Google webservice. I think you want it the other way around (try device GPS if BB Maps installed). Also, since 6.0, you need to check for net_rim_bb_maps, too.
Before you posted the update, I thought your getLatitude() and getLongitude() methods were actually fetching the device location. That was a bad assumption on my part. They were just converting numbers to strings. So, there's no reason for that to be done in the background (with a Thread). You already wrote your handleeGPS class to use a background thread, which is good. One background thread is enough. The UI that uses the location information should not also need a background Thread. I changed the code to add a GPSListener interface. That interface should be implemented by your UI code, to receive location updates. There is no reason to keep looping, asking if the location is not equal to {0.0, 0.0}. That's inefficient. With my code, you will just get notified when the location does change.
The original code was not thread safe. The handleeGPS latitude and longitude variables were set on the background thread, and accessed on the UI thread. That's not safe. Two threads should not be reading and writing the same piece of data at once. By changing the code to push location data to the GPSListener, it avoids this problem.
I uncommented the Dialog.alert() code you had inside your handleeGPS class, which would not have worked for you, because you're not allowed to make UI calls from the background. I surrounded those calls with UiApplication.getUiApplication().invokeLater() to make them safe.
To use this class, in your UI code somewhere, you would do this, instead of using a Thread to run your refreshCoordinates() method:
public void fieldChanged(Field field, int context)
// this is called when your location refresh button is clicked
GPSHandler.getInstance().setListener(this);
GPSHandler.getInstance().requestLocationUpdates();
busyDialog.setEscapeEnabled(false);
busyDialog.show();
}
...
public void onLocationReceived(Coordinates location) {
lblLatitude.setText(Double.toString(location.getLatitude()));
lblLongitude.setText(Double.toString(location.getLongitude()));
busyDialog.cancel();
}
Make sure the class where you put that code (above) also implements GPSListener, which is an interface, defined here:
public interface GPSListener {
public void onLocationReceived(Coordinates location);
}
and finally, the GPSHandler:
public class GPSHandler {
private GPSThread _gpsThread;
private Coordinates _location;
private boolean _gotLocation;
private GPSListener _listener;
/** this class will be a Singleton, as the device only has one GPS system */
private static GPSHandler _instance;
/** #return the Singleton instance of the GPSHandler */
public static GPSHandler getInstance() {
if (_instance == null) {
_instance = new GPSHandler();
}
return _instance;
}
/** not publicly accessible ... use getInstance() */
private GPSHandler() {
}
/** call this to trigger a new location fix */
public void requestLocationUpdates() {
if (_gpsThread == null || !_gpsThread.isAlive()) {
_gpsThread = new GPSThread();
_gpsThread.start();
}
}
public void setListener(GPSListener listener) {
// only supports one listener this way
_listener = listener;
}
private void setLocation(final Coordinates value) {
_location = value;
if (value.getLatitude() != 0.0 || value.getLongitude() != 0.0) {
_gotLocation = true;
if (_listener != null) {
// this assumes listeners are UI listeners, and want callbacks on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listener.onLocationReceived(value);
}
});
}
}
}
private class GPSThread extends Thread {
private void getLocationFromGoogle() {
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
writeDataGoogleMaps(outputStream2, cellID, lac);
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
final int code = dataInputStream2.readInt();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(code + "");
}
});
if (code == 0) {
final double latitude = dataInputStream2.readInt() / 1000000D;
final double longitude = dataInputStream2.readInt() / 1000000D;
setLocation(new Coordinates(latitude, longitude, 0.0f));
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(latitude+"-----"+longitude);
}
});
dataInputStream2.readInt();
dataInputStream2.readInt();
dataInputStream2.readUTF();
} else {
System.out.println("Error obtaining Cell Id ");
}
outputStream2.close();
inputStream2.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
private void tryGetLocationFromDevice() {
_gotLocation = false;
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = myLocationProvider.getLocation(300);
setLocation(myLocation.getQualifiedCoordinates());
} catch ( InterruptedException iex ) {
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
if (!_gotLocation) {
getLocationFromGoogle();
}
}
public void run() {
int bbMapsHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs"); // OS < 6.0
int bbMapsHandle60 = CodeModuleManager.getModuleHandle("net_rim_bb_maps"); // OS 6.0+
if (bbMapsHandle > 0 || bbMapsHandle60 > 0) {
tryGetLocationFromDevice();
} else {
getLocationFromGoogle();
}
}
}
private void writeDataGoogleMaps(OutputStream out, int cellID, int lac) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.writeShort(21);
dataOutputStream.writeLong(0);
dataOutputStream.writeUTF("en");
dataOutputStream.writeUTF("Android");
dataOutputStream.writeUTF("1.0");
dataOutputStream.writeUTF("Web");
dataOutputStream.writeByte(27);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(3);
dataOutputStream.writeUTF("");
dataOutputStream.writeInt(cellID);
dataOutputStream.writeInt(lac);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.flush();
}
}
There's a lot of code that we can't see (e.g. getLatitude(), getLongitude(), refreshDetails()). So, there could be something going wrong there. Also, I don't see any Loading Screen in the code you posted, so I can't say why that isn't showing.
But, here's something that doesn't look right:
synchronized (Application.getEventLock())
{
busyDialog.show();
}
If you read this BlackBerry forum question, you'll see that trying to synchronize on the application event lock from the main (UI) thread can cause your app to freeze. The public void fieldChanged(Field field, int context) method is always called on the UI thread, because it's the UI thread that monitors buttons for clicks, and calls back your click handlers, like fieldChanged().
You can also read the BlackBerry API docs for Application, that explain that getEventLock() is for worker (also known as background) threads, not the main (aka UI) thread.
So, there's no need to use special techniques to get the event lock, in code that already runs on the UI thread. Instead of the code above, just do this:
busyDialog.show();
Both of these techniques:
synchronized (Application.getEventLock())
{
busyDialog.show();
}
or
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
busyDialog.show();
}
});
are ways to safely call UI methods from a background thread. But, you shouldn't use those in code that you know is running on the UI thread already.
Try fixing that, and see if your problem disappears.
Edit: also, your code is checking for a username and password before refreshing the location. Is that really what you want? I don't think this has anything to do with your problem, but normally, I wouldn't expect to need a username or password to access location services. Of course, I don't know your application, so this is really just a comment on my part.
I think thee is simple answer is error here:
((longi == "0.0" || lati == "0.0") || (longi.length() == 0 || lati.length()==0));
You have to use String.equals() instead of == operator.
After first call longi and lati have "0.0" value. But == will return false because it compare references by default and they are different because it's different objects.
So, I'm working on my paint application. Every time I make changes, the current screen state is copied and saved as a bitmap image on my disk (so I can use it in my paint event).
The problem occurs when I minimize and return the window to its normal state and then try to draw. This triggers my event reacting to changes, the program tries to save the image ---->>> kabooom.
It says "A generic error occurred in GDI+".. So, I've been surfing through various forums in search for the answer but none of them gave me true answer, they all mention wrong paths etc. but I'm pretty sure that's not the problem. Do I have to dispose bitmap or do something with the stream?
int width = pictureBox1.Size.Width;
int height = pictureBox1.Size.Height;
Point labelOrigin = new Point(0, 0); // this is referencing the control
Point screenOrigin = pictureBox1.PointToScreen(labelOrigin);
int x = screenOrigin.X;
int y = screenOrigin.Y;
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(width, height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, bounds.Size);
}
bitmap.Save(_brojFormi + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
You're saving an image to disk so you can use it in another event? Wow.
Why not just use a class-global variable to store the bitmap?
class MyForm
{
Bitmap currentImage = null;
Graphics gfx = null;
private void btnLoad_Click(object sender, EventArgs e)
{
// ...
currentImage = new Bitmap(fileName);
gfx = Graphics.FromImage(currentImage);
}
private void pbEditor_Paint(object sender, PaintEventArgs e)
{
if (currentImage != null && gfx != null)
{
lock(currentImage) e.Graphics.DrawImage(currentImage, ...);
}
}
private void pbEditor_Click(object sender, MouseEventArgs e)
{
// quick example to show bitmap drawing
if (e.Button == MouseButtons.Left)
lock(currentImage) currentImage.SetPixel(e.Location.X, e.Location.Y, Colors.Black);
}
}
I am using mapField to create a custom map.I am using the code in this link.
How to show more than one location in Blackberry MapField?.
But the map position is fixed. i am not able to drag the map as we can do in google maps or when we invoke the maps like
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments());
}
Here's some code that should get you going on the correct path. I've taken it from a project of mine that had some special requirements, so there could be some remnants of that left in there inadvertently. There will be some undefined variables in there -- they're member variables that are declared in the class and should all start with an underscore. This is also part of a class that extends MapField, so you would have to create a custom map class and then use that rather than the default.
protected boolean touchEvent(TouchEvent message) {
boolean ret = super.touchEvent(message);
//mark that we're starting to interact
if(message.getEvent() == TouchEvent.DOWN) {
_startTouchTracking = true;
_clicking = true;
_touchX = message.getX(1);
_touchY = message.getY(1);
}
//user is wanting to move the map
else if(message.getEvent() == TouchEvent.MOVE) {
int dx = _touchX - message.getX(1);
int dy = _touchY - message.getY(1);
_clicking = false;
_touchX = message.getX(1);
_touchY = message.getY(1);
//perform checks to make sure we don't move outside of the map's range
int lat = getLatitude() - dy*(int)MathUtilities.pow(2, (double)getZoom());
if(lat < -9000000) {
lat = -9000000;
}
else if (lat > 9000000) {
lat = 9000000;
}
int lon = getLongitude() + dx*(int)MathUtilities.pow(2, (double)getZoom());
if(lon < -18000000) {
lon = -18000000;
}
else if (lon > 18000000) {
lon = 18000000;
}
moveTo(lat, lon);
}
//if the person just touches and releases, we want to move to that spot
else if (message.getEvent() == TouchEvent.UNCLICK && _clicking) {
int dx = message.getX(1) - getWidth()/2;
int dy = message.getY(1) - getHeight()/2;
move(dx, dy);
_clicking = false;
}
//touch has been released
else if (message.getEvent() == TouchEvent.UP) {
_startTouchTracking = false;
}
//we handled the click
return true;
}
As said, this might need tweaking for your use, but in general should get you started. The MathUtilities.pow() calls were my way of coming up with an appropriate amount of motion depending on the zoom level.
Edit for Comments
Letting a Bitmap move with the map:
protected Coordinates _bitmapCoordinates;
protected Bitmap _bitmap;
public YourMapField() {
//we're going to put the bitmap at -38.43, 20.32
_bitmapCoordinates = new Coordinates(-38.43, 20.32, 0.0);
_bitmap = YOUR_CODE_TO_GET_THE_BITMAP;
}
protected void paint(Graphics g) {
super.paint(g);
XYPoint placeToPaintBitmap = new XYPoint();
convertWorldToField(_bitmapCoordinates, placeToPaintBitmap);
//perform a check here to make sure that field will be seen. This code would depend
//on how you're painting the image. Just check the placeToPaintBitmap.x and placeToPaintBitmap.y
//against 0 and the map's width and height, along with some adjustment for how you paint
if(bitmap will be visible on the screen) {
//The code I have here is drawing the bitmap from the top left of the image, but if
//you need to draw from some other place you may have to offset the x and y
g.drawBitmap(placeToPaintBitmap.x, placeToPaintBitmap.y, _bitmap.getWidth(), _bitmap.getHeight(), 0, 0);
}
}
I didn't test any of that code, so it might be buggy but should give you the general idea.
I have a BlackBerry application that needs to take pictures from the camera and send them to a server. In order to do this i invoke the native camera application and listen to the filesystem. Once an image is captured and saved as a new jpeg file i get notified, resume foreground control and go about my business. The problem starts occurring after the first time this cycle is completed because now when i decide to call the camera application again it is already opened, and now the user is seeing a thumbnail of the last picture that was taken and several buttons allowing him to manipulate/manage it. naturally what i want the user to see is a preview of what the camera is "seeing" before he snaps another photo as he did before.
I have thought of various ways to solve this including killing the camera app each time (I understand this cannot be done programatically?), sending CameraArguments when invoking the app (which appears to be useless), and now i was thinking a solution could be as simple generating a "Back" key event before switching back to my app which would theoretically dismiss the annoying edit screen. Could this really be done? and if not is there any other possible solution you may think of?
A kind of hack...
start Camera App
in TimerTask check if Camera App started and if it need to be closed (some flag)
if yes, invoke it(so it will became active) and push ESC keypress event injection to close it
Take a look at this:
class Scr extends MainScreen {
boolean killCameraApp = false;
final String mCameraModuleName = "net_rim_bb_camera";
final CameraArguments args = new CameraArguments();
public Scr() {
super();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (isCameraRunning() && killCameraApp) {
getApplication().invokeAndWait(callCamera);
getApplication().invokeAndWait(killCamera);
}
}
}, 0, 100);
}
Runnable callCamera = new Runnable() {
public void run() {
callCamera();
}
};
Runnable killCamera = new Runnable() {
public void run() {
injectKey(Characters.ESCAPE);
killCameraApp = false;
}
};
private boolean isCameraRunning() {
boolean result = false;
ApplicationManager appMan =
ApplicationManager.getApplicationManager();
ApplicationDescriptor[] appDes = appMan.getVisibleApplications();
for (int i = 0; i < appDes.length; i++) {
result = mCameraModuleName.equalsIgnoreCase(appDes[i]
.getModuleName());
if (result)
break;
}
return result;
}
private void callCamera() {
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA,
new CameraArguments());
}
private void injectKey(char key) {
KeyEvent inject = new KeyEvent(KeyEvent.KEY_DOWN, key, 0);
inject.post();
}
protected void makeMenu(Menu menu, int instance) {
menu.add(new MenuItem("start camera", 0, 0) {
public void run() {
callCamera();
killCameraApp = false;
}
});
menu.add(new MenuItem("kill app", 0, 0) {
public void run() {
killCameraApp = true;
}
});
super.makeMenu(menu, instance);
}
}
EDIT: Don't forget to set permissions for device release:
Options => Advanced Options => Applications => [Your Application] =>Edit Default permissions =>Interactions =>key stroke Injection