Package com.rim.samples.device.gpsdemoadvanced

Source Code of com.rim.samples.device.gpsdemoadvanced.CoreGPSDiagnosticScreen$LocationThread$LocListener

/**
* CoreGPSDiagnosticScreen.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings.  However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies.  For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/

package com.rim.samples.device.gpsdemoadvanced;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.location.Criteria;
import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationListener;
import javax.microedition.location.LocationProvider;

import net.rim.blackberry.api.invoke.Invoke;
import net.rim.blackberry.api.invoke.MapsArguments;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.gps.GPSSettings;
import net.rim.device.api.i18n.SimpleDateFormat;
import net.rim.device.api.io.LineReader;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.EventLogger;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.CheckboxField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.TextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.StringProvider;

/**
* A screen for testing the use of the core APIs included in the
* javax.microedition.location package.
*
* There are several available modes the user can choose. (m) stands for
* 'multiple fix' and (s) stands for 'single fix'.
*
* In Smart Mode the application operates in MS-Based mode but falls back to
* MS-Assisted for a single fix if the LocationProvider is unable to return a
* valid fix in (maxInvalidTime) seconds. The provider then goes back to
* MS-Based again.
*
* For any assisted modes (all those except Stand Alone or Cellsite), additional
* helper data from a PDE server is required.
*/
public final class CoreGPSDiagnosticScreen extends MainScreen implements
        FieldChangeListener {
    // This number represents the maximum number of provider resets performed
    // before falling back to a single assisted fix. Only applies to Smart Mode.
    private static final int FALL_BACK_COUNTER_THRESHOLD = 2;

    // Provides a reference to the UiApplication for faster updating
    private final UiApplication _uiApp;

    private ObjectChoiceField _modeField;

    // Check box to indicate whether location should be displayed on a map
    private CheckboxField _enableMapLocationField;

    // Field to specify if the device uses Verizon as a carrier. If so, app
    // credentials will be set instead of PDE IP and Port.
    private CheckboxField _isVerizonField;

    // Field to specify the zoom level used in the BlackBerry Maps application
    private BasicEditField _zoomLevelField;

    // Field to enter desired horizontal accuracy. This value may be ignored in
    // the case that the selected mode requires a specific horizontal accuracy
    // value.
    private BasicEditField _horizontalAccuracyField;

    // Field to enter preferred response time
    private BasicEditField _preferredResponseTimeField;

    // Field to enter the interval parameter for a LocationListener
    private BasicEditField _frequencyField;

    // Field to enter the timeout parameter for a LocationListener
    private BasicEditField _timeoutField;

    // Field to enter the maximum age of the returned location in seconds
    private BasicEditField _maxAgeField;

    // Field to enter how long consecutive invalid fixes can occur until a
    // LocationProvider reset is performed.
    private BasicEditField _maxInvalidTimeField;

    // Displays the value returned by Location.getLocationMethod()
    private BasicEditField _currentModeField;

    // Displays the number of satellites used to compute the current fix
    private BasicEditField _currentSatelliteCountField;

    // Field to enter the PDE IP
    private BasicEditField _pdeIPField;

    // Field to enter the PDE port
    private BasicEditField _pdePortField;

    // Displays the total number of updates that have occurred
    private EditField _numberUpdatesField;

    // Displays the total number of MS-Assisted updates that have occurred
    private EditField _numberAssistedUpdatesField;

    // Displays the total number of MS-Based updates that have occurred
    private EditField _numberUnassistedUpdatesField;

    // Displays the total number of valid updates that have occurred
    private EditField _numberValidUpdatesField;

    // Displays the total number of invalid updates that have occurred
    private EditField _numberInvalidUpdatesField;

    // Displays the location information for the current fix
    private EditField _currentLocationField;

    // Displays the time of the last valid fix
    private EditField _lastValidFixField;

    // Displays the time of the last LocationProvider reset
    private EditField _lastResetField;

    // EditField to show the log messages generated during the test
    private TextField _log;

    // A Thread that performs all location related work
    private LocationThread _locThread;

    // A menu item for stopping a running test
    private final MenuItem _stopTestItem;

    private boolean _PDESet;

    /**
     * Creates a new CoreGPSDiagnosticScreen object
     */
    public CoreGPSDiagnosticScreen() {
        // Initialize reference to UiApplication
        _uiApp = UiApplication.getUiApplication();

        // Initialize UI components
        setTitle("Core GPS Diagnostic Test");
        initFields();
        _isVerizonField.setChangeListener(this);

        // A MenuItem to start the diagnostic test
        final MenuItem startTestItem =
                new MenuItem(new StringProvider("Start Test"), 0x300010, 0);
        startTestItem.setCommand(new Command(new CommandHandler() {
            /**
             * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
             *      Object)
             */
            public void execute(final ReadOnlyCommandMetadata metadata,
                    final Object context) {
                // Format the UI for output
                showOutputFields();

                if (_locThread != null) {
                    if (!_locThread.isStopped()) {
                        _locThread.stop();
                    }
                }

                _log.setText("");
                log("Core GPS API test starting");
                log("Device: " + DeviceInfo.getDeviceName());
                log("Device Software: " + DeviceInfo.getSoftwareVersion());
                log("Carrier: " + RadioInfo.getCurrentNetworkName());

                // Begin test
                _locThread = new LocationThread();
                _locThread.start();
            }
        }));
        addMenuItem(startTestItem);

        _stopTestItem =
                new MenuItem(new StringProvider("Stop Test"), 0x300020, 1);
        _stopTestItem.setCommand(new Command(new CommandHandler() {
            /**
             * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
             *      Object)
             */
            public void execute(final ReadOnlyCommandMetadata metadata,
                    final Object context) {
                // Stop the thread
                log("Stopping test");
                _locThread.stop();
                _locThread = null;
            }
        }));
        addMenuItem(_stopTestItem);

        // A MenuItem to display the help dialog
        final MenuItem helpItem =
                new MenuItem(new StringProvider("Help"), 0x300030, 2);
        helpItem.setCommand(new Command(new CommandHandler() {
            /**
             * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
             *      Object)
             */
            public void execute(final ReadOnlyCommandMetadata metadata,
                    final Object context) {
                // Display a pop-up dialog with instructions for using this
                // application
                displayHelp();
            }
        }));
        addMenuItem(helpItem);
        showInputFields();
    }

    /**
     * Initializes the UI fields
     */
    private void initFields() {
        _modeField =
                new ObjectChoiceField("Mode: ", new String[] {
                        "Stand Alone(s)", "Stand Alone(m)", "Data Optimal(m)",
                        "Speed Optimal(m)", "MS-Based(m)",
                        "Accuracy Optimal(s)", "PDE Calculate(s)",
                        "Cellsite(s)", "Cellsite(m)", "AFLT(s)",
                        "SmartMode(m)", "Default(s)", "Default(m)",
                        "NULL Criteria(s)", "NULL Criteria(m)" }, 1);
        _enableMapLocationField = new CheckboxField("Map Location", false);
        _isVerizonField = new CheckboxField("Verizon?", false);
        _zoomLevelField = new BasicEditField("Zoom: ", "1");
        _horizontalAccuracyField =
                new BasicEditField("Horizontal Accuracy (meters): ", "100", 6,
                        BasicEditField.FILTER_INTEGER);
        _preferredResponseTimeField =
                new BasicEditField("Pref'd Response Time (sec): ", "16", 6,
                        BasicEditField.FILTER_INTEGER);
        _frequencyField =
                new BasicEditField("Fix Frequency (sec): ", "5", 5,
                        BasicEditField.FILTER_INTEGER);
        _timeoutField =
                new BasicEditField("Timeout (sec): ", "-1", 5,
                        BasicEditField.FILTER_INTEGER);
        _maxAgeField =
                new BasicEditField("MaxAge (sec): ", "-1", 5,
                        BasicEditField.FILTER_INTEGER);
        _maxInvalidTimeField =
                new BasicEditField("Max Invalid Time (sec): ", "90", 5,
                        BasicEditField.FILTER_INTEGER);
        _currentModeField = new BasicEditField("Current Mode: ", "-");
        _currentSatelliteCountField = new BasicEditField("Satellites: ", "-");
        _pdeIPField = new BasicEditField("PDE IP: ", "");
        _pdePortField = new BasicEditField("PDE Port: ", "");
        _numberUpdatesField = new EditField("Total Updates: ", "0");
        _numberAssistedUpdatesField = new EditField("Assisted: ", "0");
        _numberUnassistedUpdatesField = new EditField("Unassisted: ", "0");
        _numberValidUpdatesField = new EditField("Valid Updates: ", "0");
        _numberInvalidUpdatesField = new EditField("Invalid Updates: ", "0");
        _currentLocationField = new EditField("Location: ", "-");
        _lastValidFixField = new EditField("Last Valid Fix: ", "-");
        _lastResetField = new EditField("Last Reset: ", "-");
        _log = new TextField();
        _log.setLabel("Log: ");
    }

    /**
     * Clears the screen and adds the UI input fields
     */
    private void showInputFields() {
        // Remove all current fields
        deleteAll();

        // Populate UI
        add(_modeField);
        add(new SeparatorField());
        add(_enableMapLocationField);
        add(_zoomLevelField);
        add(new SeparatorField());
        add(_horizontalAccuracyField);
        add(_preferredResponseTimeField);
        add(new SeparatorField());
        add(_frequencyField);
        add(_timeoutField);
        add(_maxAgeField);
        add(new SeparatorField());
        add(_maxInvalidTimeField);
        add(new SeparatorField());
        add(_isVerizonField);
        add(_pdeIPField);
        add(_pdePortField);
        add(new SeparatorField());
    }

    /**
     * Clears the screen and adds the UI output fields
     */
    private void showOutputFields() {
        // Remove all current fields
        deleteAll();

        // Populate UI
        add(_currentModeField);
        add(new SeparatorField());
        add(_currentLocationField);
        add(new SeparatorField());
        add(_currentSatelliteCountField);
        add(new SeparatorField());
        add(new SeparatorField());
        add(_lastValidFixField);
        add(new SeparatorField());
        add(_lastResetField);
        add(new SeparatorField());
        add(new SeparatorField());
        add(_numberUpdatesField);
        add(new SeparatorField());
        add(_numberAssistedUpdatesField);
        add(new SeparatorField());
        add(_numberUnassistedUpdatesField);
        add(new SeparatorField());
        add(_numberValidUpdatesField);
        add(new SeparatorField());
        add(_numberInvalidUpdatesField);
        add(new SeparatorField());
        add(new SeparatorField());
        add(_log);
    }

    /**
     * Displays a message in the log EditField as well as in the device event
     * log
     *
     * @param message
     *            The text to be logged
     */
    private void log(final String message) {
        if (message != null) {
            final String newMsg =
                    dateFormatter(System.currentTimeMillis()) + message + "\n";

            // Add event to device log
            EventLogger.logEvent(0x9876543212345L, newMsg.getBytes(),
                    EventLogger.ALWAYS_LOG);

            _uiApp.invokeLater(new Runnable() {
                /**
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                    // If log is too long, reset
                    if (_log.getText().length() > 1000) {
                        _log.setText("");
                    }

                    // Print message to log field
                    _log.setText(_log.getText() + newMsg);
                }
            });
        }
    }

    /**
     * Returns a String representation of a date provided in long format
     *
     * @param date
     *            Date in long format
     * @return String representation of <code>date</code>
     */
    private String dateFormatter(final long date) {
        final SimpleDateFormat sdf =
                new SimpleDateFormat(SimpleDateFormat.TIME_LONG);
        final Date d = new Date(date);
        final Calendar cal = Calendar.getInstance();
        cal.setTime(d);

        final StringBuffer buff = new StringBuffer();
        buff.append('[');
        buff.append(cal.get(Calendar.DAY_OF_MONTH));
        buff.append('-');
        buff.append(sdf.format(cal, new StringBuffer(), null).toString());
        buff.append("] ");

        return buff.toString();
    }

    /**
     * Resets the fix-related UI items to their initial values
     */
    private void resetDataFields() {
        _uiApp.invokeLater(new Runnable() {
            /**
             * @see java.lang.Runnable#run()
             */
            public void run() {
                // Replace all entered values with defaults
                _numberUpdatesField.setText("0");
                _numberAssistedUpdatesField.setText("0");
                _numberUnassistedUpdatesField.setText("0");
                _numberValidUpdatesField.setText("0");
                _numberInvalidUpdatesField.setText("0");
                _currentLocationField.setText("-");
                _currentSatelliteCountField.setText("-");
                _locThread._lastValid = System.currentTimeMillis();
                _lastValidFixField
                        .setText(dateFormatter(_locThread._lastValid));
                _lastResetField.setText(dateFormatter(_locThread._lastReset));
                _currentModeField.setText("-");
            }
        });
    }

    /**
     * All location related tasks are performed in this Thread
     */
    private final class LocationThread extends Thread {
        /**
         * If true, the app will use a LocationListener to continually provide
         * updates with regard to location. If false, a single call to
         * LocationProvider.getLocation() will be made.
         */
        private boolean _isMultipleFixes = true;

        /*
         * If > FALL_BACK_COUNTER_THRESHOLD, a single fallBack fix will be
         * computed in MS-Assisted mode. This is only used in SmartMode.
         */
        private int _fallBackCounter = FALL_BACK_COUNTER_THRESHOLD;

        /*
         * In SmartMode the application operates mostly in MS-Based mode but
         * falls back to MS-Assisted for a single fix if the LocationProvider is
         * unable to return a valid fix after the number of resets reaches
         * FALL_BACK_COUNTER_THRESHOLD. If the number of resets exceeds
         * FALL_BACK_COUNTER_THRESHOLD, a single assisted fix will be computed.
         * A reset is performed if the provider fails to return a valid fix for
         * more than "maxInvalidTimeField.getText()" seconds. The provider then
         * goes back to MS-Based mode again.
         */
        private boolean _isSmartMode;

        // Determines the mode of the LocationProvider
        private Criteria _criteria;

        // Arguments passed to LocationProvider.setLocationListener()
        private final int _frequency, _timeout, _maxage;

        // Counter variables for valid, invalid, assisted, unassisted and total
        // updates
        private int _totalUpdates, _validUpdates, _inValidUpdates,
                _assistedUpdates, _unassistedUpdates;

        // Reference to the LocationProvider
        private LocationProvider _provider;

        // Variable to store the date/time (in long format) of the last valid
        // fix
        private long _lastValid = System.currentTimeMillis();

        // Variable to store the date/time (in long format) of the last
        // LocationProvider reset
        private long _lastReset = System.currentTimeMillis();

        // Location object that holds the current location at a given time
        private Location _location = null;

        // Indicates whether the thread has been stopped
        private boolean _isStopped;

        /**
         * Creates a new LocationThread object. Initializes frequency, timeout
         * and max age counters and sets PDE parameters according to the PDE IP
         * and PORT provided by the user.
         */
        LocationThread() {
            _frequency = Integer.parseInt(_frequencyField.getText());
            _timeout = Integer.parseInt(_timeoutField.getText());
            _maxage = Integer.parseInt(_maxAgeField.getText());
        }

        /*
         * Sets up the PDE server
         */
        private void setupPDE() {
            final String pdeIPText = _pdeIPField.getText();
            final String pdePortText = _pdePortField.getText();

            if (pdeIPText.length() > 0) {
                if (!_isVerizonField.getChecked()) {
                    log("Using PDE: " + pdeIPText + ":" + pdePortText);
                    final boolean setPDESuccess =
                            GPSSettings.setPDEInfo(pdeIPText, Integer
                                    .parseInt(pdePortText));
                    if (setPDESuccess) {
                        _PDESet = true;
                        log("setPDEInfo() successful");
                    }
                } else {
                    // Set Verizon specific settings
                    log("Using VZ Credentials: " + ";" + pdeIPText + ";"
                            + pdePortText);
                    GPSSettings.setPDEInfo(";" + pdeIPText + ";" + pdePortText,
                            0);

                    // Verizon Verizon PDE server sessions time out after
                    // 12 hours. Set up a timer to reset the connection
                    // at ~12 hour intervals.
                    final Timer timer = new Timer();

                    final TimerTask task = new TimerTask() {
                        /**
                         * @see java.util.TimerTask#run()
                         */
                        public void run() {
                            clearVerizonCredential();
                            setupPDE();
                            resetProvider();
                            setupProvider();
                        }
                    };

                    // Set period to just under 12 hours
                    final long period = 1000 * 60 * 60 * 12 - 60000;

                    // Set date to just under 12 hours from now
                    long date = new Date().getTime();
                    date = date + period;

                    timer.scheduleAtFixedRate(task, period, date);
                    _PDESet = true;
                }
            }
        }

        /**
         * This method validates the value in the _horizontalAccuracy EditField.
         * If mustBeZero is true then the value is set to 0. Otherwise, the user
         * specified value is validated i.e. if the user sets a value < = 0 the
         * value is force set to a default value of 100.
         *
         * @param mustBeZero
         *            True if the value must be 0, false otherwise
         */
        private void validateHorizontalAccuracy(final boolean mustBeZero) {
            _uiApp.invokeLater(new Runnable() {
                /**
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                    final int value =
                            Integer.parseInt(_horizontalAccuracyField.getText());
                    if (!mustBeZero) {
                        if (value <= 0) {
                            _horizontalAccuracyField.setText("100");
                        }
                    } else {
                        _horizontalAccuracyField.setText("0");
                    }
                }
            });
        }

        /**
         * @see java.lang.Thread#run()
         */
        public void run() {
            resetDataFields();
            setupCriteria();

            log("Criteria initialized");

            if (!_PDESet) {
                setupPDE();
            }

            log("Starting Updates: "
                    + dateFormatter(System.currentTimeMillis()));
            setupProvider();
        }

        /**
         * Resets logic for most carriers (excludes Verizon)
         */
        private void resetProvider() {
            // Set to indicate that the provider has been reset
            _lastReset = System.currentTimeMillis();
            _uiApp.invokeLater(new Runnable() {
                /**
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                    // Indicate in the UI that the provider is being reset
                    _lastResetField.setText(dateFormatter(_lastReset));
                }
            });
            log("Resetting LocationProvider");
            _provider.setLocationListener(null, 0, 0, 0);
            _provider.reset();
            _provider = null;
        }

        /**
         * Resets credential logic for Verizon. Also refreshes the Verizon PDE
         * session which needs to be done every 12 hours (contact Verizon).
         */
        private void clearVerizonCredential() {
            final Thread resetThread = new Thread() {
                /**
                 * @see java.lang.Thread#run()
                 */
                public void run() {
                    LocationProvider tempProvider = null;

                    try {
                        tempProvider = LocationProvider.getInstance(_criteria);
                    } catch (final LocationException e) {
                        log(e.toString());
                    }

                    if (tempProvider != null) {
                        log("Clearing VZ credentials. Please wait...");

                        try {
                            Thread.sleep(2000);
                        } catch (final InterruptedException e) {
                            log(e.toString());
                        }

                        GPSSettings.setPDEInfo("127.0.0.1", 0);

                        try {
                            // Sleep so the PDE has time to be set up
                            Thread.sleep(2000);
                        } catch (final InterruptedException e) {
                            log(e.toString());
                        }

                        try {
                            tempProvider.getLocation(1);
                        } catch (final Exception e) {
                            log(e.toString());
                        }

                        try {
                            Thread.sleep(15000);
                        } catch (final InterruptedException e) {
                            log(e.toString());
                        }

                        tempProvider = null;
                        log("Old Verizon session cleared.");
                    }
                }
            };

            resetThread.start();
            try {
                resetThread.join();
            } catch (final InterruptedException e) {
                log(e.toString());
            }
        }

        /**
         * Initializes criteria according to the mode selected by the user. The
         * following algorithm is used: If costAllowed = FALSE mode is Stand
         * Alone Otherwise, if costAllowed=TRUE, -if horizontalAccuracy = 0,
         * mode is Data Optimal -if horizontalAccuracy > 0, -if multiplied fixes
         * requested, -if Telus, mode is MS-based -otherwise, -if powerUsage =
         * HIGH, mode is Speed Optimal; -if powerUsage != HIGH, mode is MS-based
         * -else if single fix requested, -if powerUsage = HIGH, mode is
         * Accuracy Optimal -if powerUsage != HIGH, mode is PDE Calculate -if
         * powerUsage = LOW mode is Cellsite
         */
        private void setupCriteria() {
            _criteria = new Criteria();
            _criteria.setPreferredResponseTime(Integer
                    .parseInt(_preferredResponseTimeField.getText()));

            switch (_modeField.getSelectedIndex()) {
            case 0: // Stand Alone(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria.setCostAllowed(false);
                validateHorizontalAccuracy(false);
                _criteria.setVerticalAccuracy(200);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                log("Criteria set for Stand Alone");
                break;
            case 1: // Stand Alone(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria.setCostAllowed(false);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                log("Criteria set for Stand Alone");
                break;
            case 2: // Data Optimal(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
                _criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
                log("Criteria set for Data Optimal");
                break;
            case 3: // Speed Optimal(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_HIGH);
                log("Criteria set for Speed Optimal");
                break;
            case 4: // MS-Based(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_MEDIUM);
                log("Criteria set for MS-Based");
                break;
            case 5: // Accuracy Optimal(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_HIGH);
                log("Criteria set for Accuracy Optimal");
                break;
            case 6: // PDE Calculate(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_MEDIUM);
                log("Criteria set for PDE Calculate");
                break;
            case 7: // Cellsite(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                _criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
                _criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
                log("Criteria set for Cellsite(s)");
                break;
            case 8: // Cellsite(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                _criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
                _criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_LOW);
                log("Criteria set for Cellsite(m)");
                break;
            case 9: // AFLT(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_MEDIUM);
                _criteria.setPreferredResponseTime(0);
                log("Criteria set for AFLT");
                break;
            case 10: // SmartMode(m)
                _isMultipleFixes = true;
                _isSmartMode = true;
                _criteria.setCostAllowed(true);
                validateHorizontalAccuracy(false);
                _criteria.setHorizontalAccuracy(Integer
                        .parseInt(_horizontalAccuracyField.getText()));
                _criteria.setVerticalAccuracy(200);
                _criteria
                        .setPreferredPowerConsumption(Criteria.POWER_USAGE_MEDIUM);
                log("Criteria set for Smart Mode");
                break;
            case 11: // default criteria(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                log("Criteria set for Default Criteria");
                break;
            case 12: // default criteria(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                log("Criteria set for Default Criteria");
                break;
            case 13: // null criteria(s)
                _isMultipleFixes = false;
                _isSmartMode = false;
                _criteria = null;
                log("Criteria set to null");
                break;
            case 14: // null criteria(m)
                _isMultipleFixes = true;
                _isSmartMode = false;
                _criteria = null;
                log("Criteria set to null");
                break;
            }
        }

        /**
         * This method initializes the LocationProvider and sets a
         * LocationListener if <code>isMultipleFixes</code> is TRUE. Otherwise
         * it simply calls singleFixLocationUpdate() which calls
         * LocationProvider.getLocation() once to get a single fix.
         */
        private void setupProvider() {
            try {
                log("setupProvider()");

                try {
                    // Sleep to give _provider and _criteria enough time to
                    // instantiate
                    Thread.sleep(5000);
                } catch (final InterruptedException ie) {
                    log(ie.toString());
                }

                _provider = LocationProvider.getInstance(_criteria);
                log("LocationProvider initialized");

                if (_provider != null) {
                    if (_isMultipleFixes && _isSmartMode
                            && _fallBackCounter < FALL_BACK_COUNTER_THRESHOLD
                            || _isMultipleFixes && !_isSmartMode) {
                        // Multifix non-SmartMode or SmartMode going back to
                        // MS-Based
                        if (_isSmartMode) {
                            log("SmartMode in MS-Based mode - fallBackCounter: "
                                    + _fallBackCounter);
                        }
                        _provider.setLocationListener(new LocListener(),
                                _frequency, _timeout, _maxage);
                        log("LocationListener started");
                    } else {
                        // Single fix non-SmartMode or SmartMode Falling back to
                        // MS-Assisted
                        if (_isSmartMode) {
                            log("SmartMode in MS-Assisted mode - fallBackCounter: "
                                    + _fallBackCounter);
                        }

                        log("Initiating single shot GPS fix");
                        singleFixLocationUpdate();
                    }
                } else {
                    log("Provider unavailable for Criteria");
                }
            } catch (final LocationException le) {
                log(le.toString());
            }
        }

        /**
         * Gets a single fix by calling LocationProvider.getLocation(). Updates
         * the UI with the fix information. In case of a valid fix it maps the
         * fix by invoking the Maps application.
         */
        private void singleFixLocationUpdate() {
            try {
                _location = _provider.getLocation(100);
            } catch (final InterruptedException ie) {
                log("InterruptedException thrown by getLocation(): "
                        + ie.getMessage());
            } catch (final LocationException le) {
                log("LocationException thrown by getLocation(): "
                        + le.getMessage());
            }

            if (_location != null) {
                _uiApp.invokeLater(new Runnable() {
                    /**
                     * @see java.lang.Runnable#run()
                     */
                    public void run() {
                        _numberUpdatesField.setText(Integer
                                .toString(++_totalUpdates));
                    }
                });

                if (_location.isValid()) {
                    _lastValid = System.currentTimeMillis();

                    // Update UI to reflect new location
                    _uiApp.invokeLater(new Runnable() {
                        /**
                         * @see java.lang.Runnable#run()
                         */
                        public void run() {
                            _lastValidFixField
                                    .setText(dateFormatter(_lastValid));
                            _currentModeField
                                    .setText(getLocMethodString(_location
                                            .getLocationMethod()));

                            final StringBuffer buff = new StringBuffer();
                            buff.append(_location.getQualifiedCoordinates()
                                    .getLatitude());
                            buff.append(' ');
                            buff.append(_location.getQualifiedCoordinates()
                                    .getLongitude());
                            buff.append(' ');
                            buff.append(_location.getQualifiedCoordinates()
                                    .getAltitude());
                            buff.append(' ');
                            _currentLocationField.setText(buff.toString());

                            _currentSatelliteCountField
                                    .setText(getNumSatellites(_location));
                            _numberValidUpdatesField.setText(Integer
                                    .toString(++_validUpdates));
                            _numberAssistedUpdatesField.setText(Integer
                                    .toString(++_assistedUpdates));
                        }
                    });

                    final StringBuffer logText =
                            new StringBuffer("Valid single fix: ");
                    logText.append(_location.getQualifiedCoordinates()
                            .getLatitude());
                    logText.append(", ");
                    logText.append(_location.getQualifiedCoordinates()
                            .getLongitude());
                    logText.append(' ');
                    logText.append(_location.getQualifiedCoordinates()
                            .getAltitude());
                    log(logText.toString());
                    log("Method: "
                            + getLocMethodString(_location.getLocationMethod()));

                    // If Smart Mode, go back to MS-Based
                    if (_isSmartMode) {
                        log("Smart Mode got single MS-Assisted fix");
                        _fallBackCounter = 0;
                        resetProvider();
                        setupProvider();
                    }

                    if (_enableMapLocationField.getChecked()) {
                        // Launch Maps application with current location
                        displayLocationOnMap(_location);
                    }
                } else {
                    // Update UI to reflect invalid location
                    _uiApp.invokeLater(new Runnable() {
                        /**
                         * @see java.lang.Runnable#run()
                         */
                        public void run() {
                            _currentLocationField.setText("Invalid");
                            _currentSatelliteCountField.setText("-");
                            _numberInvalidUpdatesField.setText(Integer
                                    .toString(++_inValidUpdates));
                        }
                    });
                    log("Invalid single fix");

                    // Check if invalid fixes have exceeded allowed time
                    if (System.currentTimeMillis() - _lastValid >= Integer
                            .parseInt(_maxInvalidTimeField.getText()) * 1000
                            && System.currentTimeMillis() - _lastReset >= Integer
                                    .parseInt(_maxInvalidTimeField.getText()) * 1000
                            || System.currentTimeMillis() - _lastReset >= Integer
                                    .parseInt(_maxInvalidTimeField.getText()) * 1000) {
                        final StringBuffer logText =
                                new StringBuffer(
                                        "Resetting Location Provider because: \nInvalid fixes for ");
                        logText.append((System.currentTimeMillis() - _lastValid) / 1000);
                        logText.append(" seconds\nNo provider reset for ");
                        logText.append((System.currentTimeMillis() - _lastReset) / 1000);
                        logText.append(" seconds");
                        log(logText.toString());

                        // If Smart Mode, go back to MS-Based
                        if (_isSmartMode) {
                            log("Smart Mode failed to get single MS-Assisted fix");
                            _fallBackCounter = 0;
                            resetProvider();
                            setupProvider();
                        }

                        resetProvider();
                        setupProvider();
                    }
                }
            } else {
                log("Location is null");

                // If Smart Mode, go back to MS-Based
                if (_isSmartMode) {
                    log("Smart Mode FAILED! to get single MS-Assisted fix");
                    _fallBackCounter = 0;
                    resetProvider();
                    setupProvider();
                }
            }
        }

        /**
         * Invoke the Maps application to show a fix on a map
         *
         * @param location
         *            The location object to display on map
         */
        private void displayLocationOnMap(final Location location) {
            try {
                String lon =
                        Double.toString(location.getQualifiedCoordinates()
                                .getLongitude() * 100000);
                lon = lon.substring(0, 8);
                String lat =
                        Double.toString(location.getQualifiedCoordinates()
                                .getLatitude() * 100000);
                lat = lat.substring(0, 7);

                final StringBuffer document =
                        new StringBuffer("<lbs><location lon='");
                document.append(lon);
                document.append("' lat='");
                document.append(lat);
                document.append("' label='MyLocation' zoom='");
                document.append(_zoomLevelField.getText());
                document.append("'/></lbs>");

                // Launch Maps application
                Invoke.invokeApplication(Invoke.APP_TYPE_MAPS,
                        new MapsArguments(MapsArguments.ARG_LOCATION_DOCUMENT,
                                document.toString()));
            } catch (final Exception e) {
                log("Unable to map Location. Please make sure that BlackBerry Maps is installed.");
            }
        }

        /**
         * Returns a String representation of the location process being used
         *
         * @param method
         *            The the location method for which to retrieve a string
         * @return Location method string
         */
        private String getLocMethodString(final int method) {
            final StringBuffer buf = new StringBuffer();
            if ((method & Location.MTA_ASSISTED) != 0) {
                buf.append("*MTA_ASSISTED");
            }
            if ((method & Location.MTA_UNASSISTED) != 0) {
                buf.append("*MTA_UNASSISTED");
            }
            if ((method & Location.MTE_ANGLEOFARRIVAL) != 0) {
                buf.append("*MTE_ANGLEOFARRIVAL");
            }
            if ((method & Location.MTE_CELLID) != 0) {
                buf.append("*MTE_CELLID");
            }
            if ((method & Location.MTE_SATELLITE) != 0) {
                buf.append("*MTE_SATELLITE");
            }
            if ((method & Location.MTE_SHORTRANGE) != 0) {
                buf.append("*MTE_SHORTRANGE");
            }
            if ((method & Location.MTE_TIMEDIFFERENCE) != 0) {
                buf.append("*MTE_TIMEDIFFERENCE");
            }
            if ((method & Location.MTE_TIMEOFARRIVAL) != 0) {
                buf.append("*MTE_TIMEOFARRIVAL");
            }
            if ((method & Location.MTY_NETWORKBASED) != 0) {
                buf.append("*MTY_NETWORKBASED");
            }
            if ((method & Location.MTY_TERMINALBASED) != 0) {
                buf.append("*MTY_TERMINALBASED");
            }
            buf.append("*");

            return buf.toString();
        }

        /**
         * Retrieve the satellite data for a given location
         *
         * @param location
         *            The location to retrieve information for
         * @return A string describing the number of available satellites
         */
        private String getNumSatellites(final Location location) {
            String extra =
                    location.getExtraInfo("application/X-jsr179-location-nmea");

            // Retrieve the eighth section of the comma-delimited extra string
            for (int i = 0; i < 7; i++) {
                extra = extra.substring(extra.indexOf(',') + 1, extra.length());
            }

            return extra.substring(0, extra.indexOf(','));
        }

        /**
         * Resets the BlackBerryLocationProvider and removes reference
         */
        public void stop() {
            _isStopped = true;

            // Log the statistics for the location session
            log("Stopping Updates: "
                    + dateFormatter(System.currentTimeMillis()));
            log("Total Updates: " + _numberUpdatesField);
            log("Assisted Updates: " + _numberAssistedUpdatesField);
            log("Unassisted Updates: " + _numberUnassistedUpdatesField);
            log("Valid Updates: " + _numberValidUpdatesField);
            log("Invalid Updates: " + _numberInvalidUpdatesField);

            if (_provider != null) {
                _provider.setLocationListener(null, 0, 0, 0);
                _provider.reset();
                _provider = null;
            }
        }

        /**
         * Returns the running/stopped status of this thread
         *
         * @return The running/stopped status of this thread
         */
        boolean isStopped() {
            return _isStopped;
        }

        /**
         * LocationListener implementation
         */
        private class LocListener implements LocationListener {
            // Flag indicating an immediate reset is required due
            // to TEMPORARILY_UNAVAILABLE event.
            boolean _resetNow;

            /**
             * @see javax.microedition.location.LocationListener#locationUpdated(LocationProvider,
             *      Location)
             */
            public void locationUpdated(final LocationProvider provider,
                    final Location location) {
                _uiApp.invokeLater(new Runnable() {
                    /**
                     * @see java.lang.Runnable#run()
                     */
                    public void run() {
                        _numberUpdatesField.setText(Integer
                                .toString(++_totalUpdates));
                    }
                });

                if (location.isValid()) {
                    _lastValid = System.currentTimeMillis();
                    _uiApp.invokeLater(new Runnable() {
                        /**
                         * @see java.lang.Runnable#run()
                         */
                        public void run() {
                            // Update UI to reflect new location
                            _lastValidFixField
                                    .setText(dateFormatter(_lastValid));
                            _currentModeField
                                    .setText(getLocMethodString(location
                                            .getLocationMethod()));

                            final StringBuffer buff = new StringBuffer();
                            buff.append(location.getQualifiedCoordinates()
                                    .getLatitude());
                            buff.append(' ');
                            buff.append(location.getQualifiedCoordinates()
                                    .getLongitude());
                            buff.append(' ');
                            buff.append(location.getQualifiedCoordinates()
                                    .getAltitude());
                            buff.append(' ');
                            _currentLocationField.setText(buff.toString());

                            _currentSatelliteCountField
                                    .setText(getNumSatellites(location));
                            _numberValidUpdatesField.setText(Integer
                                    .toString(++_validUpdates));
                            _numberUnassistedUpdatesField.setText(Integer
                                    .toString(++_unassistedUpdates));
                        }
                    });

                    final StringBuffer buff =
                            new StringBuffer("Valid multiple fix: ");
                    buff.append(location.getQualifiedCoordinates()
                            .getLatitude());
                    buff.append(", ");
                    buff.append(location.getQualifiedCoordinates()
                            .getLongitude());
                    buff.append(' ');
                    buff.append(location.getQualifiedCoordinates()
                            .getAltitude());
                    log(buff.toString());

                    log("Method: "
                            + getLocMethodString(location.getLocationMethod()));

                    // If map location enabled, launch Maps application
                    if (_enableMapLocationField.getChecked()) {
                        displayLocationOnMap(location);
                    }
                } else {
                    if (_resetNow) {
                        resetProvider();
                        setupProvider();
                        return;
                    }

                    _uiApp.invokeLater(new Runnable() {
                        /**
                         * @see java.lang.Runnable#run()
                         */
                        public void run() {
                            _currentLocationField.setText("Invalid");
                            _currentSatelliteCountField.setText("-");
                            _numberInvalidUpdatesField.setText(Integer
                                    .toString(++_inValidUpdates));
                        }
                    });
                    log("Invalid multiple fix");

                    // If invalid fixes have exceeded allowed time, reset the
                    // location provider
                    if (System.currentTimeMillis() - _lastValid >= Integer
                            .parseInt(_maxInvalidTimeField.getText()) * 1000
                            && System.currentTimeMillis() - _lastReset >= Integer
                                    .parseInt(_maxInvalidTimeField.getText()) * 1000
                            || System.currentTimeMillis() - _lastReset >= Integer
                                    .parseInt(_maxInvalidTimeField.getText()) * 1000) {
                        final StringBuffer buff =
                                new StringBuffer(
                                        "Resetting Location Provider because: \nInvalid fixes for ");
                        buff.append((System.currentTimeMillis() - _lastValid)
                                / 1000 + " seconds \nNo provider reset for ");
                        buff.append((System.currentTimeMillis() - _lastReset)
                                / 1000 + " seconds");
                        log(buff.toString());

                        if (_isSmartMode) {
                            _fallBackCounter++;
                        }
                        resetProvider();
                        setupProvider();
                    }
                }
            }

            /**
             * @see javax.microedition.location.LocationListener#providerStateChanged(LocationProvider,
             *      int)
             */
            public void providerStateChanged(final LocationProvider provider,
                    final int newState) {
                switch (newState) {
                case LocationProvider.OUT_OF_SERVICE: // Triggered when a BES
                                                      // policy does not allow
                                                      // location capabilities
                    log("State Change: Out of Service");
                    break;
                case LocationProvider.TEMPORARILY_UNAVAILABLE: // Triggered when
                                                               // the system has
                                                               // stopped
                                                               // looking for a
                                                               // fix and went
                                                               // cold
                    log("State Change: Temp Unavailable");

                    // This is set to indicate that the provider has been reset
                    _lastValid = System.currentTimeMillis();
                    _uiApp.invokeLater(new Runnable() {
                        /**
                         * @see java.lang.Runnable#run()
                         */
                        public void run() {
                            _lastValidFixField
                                    .setText(dateFormatter(_lastValid));
                        }
                    });

                    log("Resetting Location Provider due to TEMPORARILY UNAVAILABLE state");

                    if (_isSmartMode) {
                        log("Smart Mode resetting...");
                        _fallBackCounter++;
                        _resetNow = true;
                    } else {
                        _resetNow = true;
                    }
                    break;
                }
            }
        }
    }

    /**
     * @see net.rim.device.api.ui.Screen#onClose()
     */
    public boolean onClose() {
        log("Closing Application");

        if (_locThread != null) {
            _locThread.stop();
            _locThread = null;
        }

        return super.onClose();
    }

    /**
     * @see net.rim.device.api.ui.Screen#onSavePrompt()
     */
    public boolean onSavePrompt() {
        // Suppress the save dialog
        return true;
    }

    /**
     * @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu, int)
     */
    protected void makeMenu(final Menu menu, final int instance) {
        super.makeMenu(menu, instance);

        if (_locThread != null) {
            menu.setDefault(_stopTestItem);
        }
    }

    /**
     * @see net.rim.device.api.ui.FieldChangeListener#fieldChanged(Field, int)
     */
    public void fieldChanged(final Field field, final int context) {
        if (field == _isVerizonField) {
            if (_isVerizonField.getChecked()) {
                _pdeIPField.setLabel("Client ID: ");
                _pdePortField.setLabel("Password: ");
            } else {
                _pdeIPField.setLabel("PDE IP: ");
                _pdePortField.setLabel("PDE Port: ");
            }
        }
    }

    /**
     * Displays the help dialog
     */
    private void displayHelp() {
        final InputStream stream =
                getClass().getResourceAsStream("/resource/help_core.txt");
        final LineReader lineReader = new LineReader(stream);
        final StringBuffer help = new StringBuffer();

        for (;;) {
            try {
                help.append(new String(lineReader.readLine()));
                help.append('\n');
            } catch (final EOFException eof) {
                // We've reached the end of the file
                break;
            } catch (final IOException ioe) {
                Dialog.alert("LineReader#readLine() threw " + ioe.toString());
                return;
            }
        }

        Dialog.inform(help.toString());
    }
}
TOP

Related Classes of com.rim.samples.device.gpsdemoadvanced.CoreGPSDiagnosticScreen$LocationThread$LocListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.