www.pudn.com > GMapViewer-src.zip > GMapViewer.java
package org.sreid.j2me.gmapviewer;
import java.util.*;
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.microedition.midlet.*;
import org.sreid.j2me.util.*;
public class GMapViewer extends MIDlet {
final boolean debug = false;
/** This MIDlet's display. */
final Display display;
/** User preferences (persistent). */
final Preferences prefs;
/** Shared chunks of memory (byte array(s)), allocated before memory gets fragmented so as to avoid heap compaction later on. */
final ResourcePool sharedBuffers;
/** Background worker thread(s) used for: downloading map tiles */
final AsyncProcessor async1;
/** Background worker thread(s) used for: decoding map tiles, submitting searches */
final AsyncProcessor async2;
final GMapCanvas canvas;
final MapTileCache cache;
final MapTileManager mtm;
final MapPinManager mpm;
final MainMenu mainMenu;
final MapPinMenu mapPinMenu;
final SearchMenu searchMenu;
final PrefsEditor prefsEditor;
final Vector log = new Vector();
private boolean hideErrors = false;
private boolean clean; // if false, cleanup still needs to be run
boolean online = true;
public GMapViewer() {
display = Display.getDisplay(this);
prefs = new Preferences(this);
prefs.loadPreferences();
boolean success = false;
try {
int dt = prefs.getInt("downloadThreads", 1);
if (dt < 1) dt = 1;
if (dt > 4) dt = 4;
byte[][] sb = new byte[dt][];
for (int i = 0; i < dt; i++) {
sb[i] = new byte[32000];
}
sharedBuffers = new ResourcePool(sb);
async1 = new AsyncProcessor(dt);
async2 = new AsyncProcessor(1);
canvas = new GMapCanvas(this);
cache = new MapTileCache(this);
mtm = new MapTileManager(this); // depends: cache
mpm = new MapPinManager(this);
mainMenu = new MainMenu(this);
mapPinMenu = new MapPinMenu(this);
searchMenu = new SearchMenu(this);
prefsEditor = new PrefsEditor(this); // depends: prefs
success = true;
}
finally {
if (!success) {
try {
// Some kind of exception/error, probably user set downloadThreads too high.
prefs.put("downloadThreads", "1");
prefs.savePreferences();
}
catch (Throwable t) { }
}
}
}
public void startApp() {
debug("startApp()");
clean = false;
canvas.loadPosition();
cache.openRMS();
mpm.openRMS();
mapPinMenu.loadList();
display.setCurrent(mainMenu);
canvas.repaint();
// Clean up obsolete preferences
String[] unused = new String[] { "canvas.xpos", "canvas.xoff", "canvas.ypos", "canvas.yoff" };
for (int i = 0; i < unused.length; i++) {
prefs.remove(unused[i]);
}
}
public void pauseApp() {
debug("pauseApp()");
cleanup();
}
public void destroyApp(boolean unconditional) {
debug("destroyApp()");
if (!clean) cleanup();
notifyDestroyed();
}
void quit() {
if (clean) destroyApp(false);
Dialog dlg = Dialog.createConfirmationDialog("Closing GMapViewer", "Closing GMapViewer. This may take a while. Please wait...", "", "");
dlg.showOn(this, dlg);
async2.enqueueJob(new Runnable() { public void run() {
destroyApp(false);
}});
}
private void cleanup() {
if (clean) return;
cache.compact();
canvas.savePosition();
prefs.savePreferences();
cache.closeRMS();
mpm.closeRMS();
clean = true;
debug("cleanup() done");
}
void debug(Object info) {
if (debug) {
System.err.println(info);
}
}
void exception(String message, Throwable exception) {
try {
if (debug) {
System.err.println(message);
exception.printStackTrace();
}
log.addElement(message + "\n" + exception + "\n-----\n");
if (log.size() > 20) log.removeElementAt(0);
if (!hideErrors && mainMenu != null) {
final Dialog dlg = Dialog.createConfirmationDialog("Error", message + "\n\nSee the error log (from the main menu) for more details.", "OK", "Hide errors");
dlg.setCallback(new Runnable() { public void run() {
if (dlg.getUserResponse() == null) {
hideErrors = true;
}
}});
dlg.showSerially(this, mainMenu);
}
}
catch (Throwable t) {
// Exception while handling an exception. Very bad, but can't do much about it.
t.printStackTrace();
}
}
void alert(final Alert alert) {
display.setCurrent(alert, display.getCurrent());
}
void alert(String title, String message) {
Alert a = new Alert(title, message, null, null);
//a.setTimeout(Alert.FOREVER);
alert(a);
}
/**
* Loads data from the server, checking our special 5-byte header.
* @param action the action specifier
* @param params URL parameters, must start with &.
* @param buffer the buffer to load data in to. Must be large enough to contain all the data.
* @param expectedHeader the expected header word.
* @return the number of bytes actually read
*/
int getDataFromServer(String action, String params, byte[] buffer, String expectedHeader) throws IOException {
ContentConnection conn = null;
InputStream in = null;
try {
String url = prefs.getString("gatewayURL", "") + "?p=" + prefs.getString("gatewayAuth", "") + "&a=" + action + params;
debug("Fetching URL: " + url);
conn = (ContentConnection)Connector.open(url);
in = conn.openInputStream();
// Get special 5-byte header
StringBuffer sb = new StringBuffer();
for (;;) {
int c = in.read();
if (c == -1 || c == (int)':') break;
sb.append((char)c);
}
String header = sb.toString();
// Read data
int count = 0;
for (;;) {
int c = in.read(buffer, count, buffer.length - count);
if (c < 0) break;
count += c;
if (count >= buffer.length) break;
}
if (header.equals(expectedHeader)) {
return count;
}
else if (header.equals("ERROR")) {
throw new IOException("Server reported error: " + new String(buffer, 0, count));
}
else {
throw new IOException("Invalid response from server: " + Util.bytesToHex(buffer, 0, count));
}
}
finally {
try { if (in != null) in.close(); } catch (Exception e) { }
try { if (conn != null) conn.close(); } catch (Exception e) { }
}
}
}