Android Open Source - wigle-wifi-wardriving-badfork List Activity






From Project

Back to project page wigle-wifi-wardriving-badfork.

License

The source code is released under:

/* * Copyright (c) 2010-2012, Andrew Carra, Robert Hagemann, Hugh Kennedy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permi...

If you think the Android project wigle-wifi-wardriving-badfork listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

// -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vim:ts=2:sw=2:tw=80:et
//  w w  w .  j  av a2s  .  c o m
package net.wigle.wigleandroid;

import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import net.wigle.wigleandroid.MainActivity.Doer;
import net.wigle.wigleandroid.background.FileUploaderListener;
import net.wigle.wigleandroid.background.FileUploaderTask;
import net.wigle.wigleandroid.listener.BatteryLevelReceiver;
import net.wigle.wigleandroid.listener.GPSListener;
import net.wigle.wigleandroid.listener.PhoneState;
import net.wigle.wigleandroid.listener.PhoneStateFactory;
import net.wigle.wigleandroid.listener.WifiReceiver;

import org.osmdroid.util.GeoPoint;

import android.app.Activity;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
import android.os.IBinder;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

public final class ListActivity extends Activity implements FileUploaderListener {
    // *** state that is retained ***
    private static class State {
      private DatabaseHelper dbHelper;
      private ServiceConnection serviceConnection;
      private AtomicBoolean finishing;
      private AtomicBoolean transferring;
      private MediaPlayer soundPop;
      private MediaPlayer soundNewPop;
      private WifiLock wifiLock;
      private GPSListener gpsListener;
      private WifiReceiver wifiReceiver;
      private NumberFormat numberFormat0;
      private NumberFormat numberFormat1;
      private NumberFormat numberFormat8;
      private TTS tts;
      private boolean inEmulator;
      private BatteryLevelReceiver batteryLevelReceiver;
      private PhoneState phoneState;
      private FileUploaderTask fileUploaderTask;
    }
    private State state;
    // *** end of state that is retained ***
    
    private NetworkListAdapter listAdapter;
    private String previousStatus;
    
    public static final String FILE_POST_URL = "https://wigle.net/gps/gps/main/confirmfile/";
    public static final String OBSERVED_URL = "https://wigle.net/gps/gps/main/myobserved/";
    private static final String LOG_TAG = "wigle";
    private static final int MENU_SETTINGS = 10;
    private static final int MENU_EXIT = 11;
    private static final int MENU_WAKELOCK = 12;
    private static final int MENU_SORT = 13;
    private static final int MENU_SCAN = 14;
    private static final int MENU_FILTER = 15;
    
    private static final int SORT_DIALOG = 100;
    private static final int SSID_FILTER = 102;
    
    public static final String ENCODING = "ISO-8859-1";
    public static final float MIN_DISTANCE_ACCURACY = 32f;
    static final String ERROR_STACK_FILENAME = "errorstack";
    static final String ERROR_REPORT_DO_EMAIL = "doEmail";
    static final String ERROR_REPORT_DIALOG = "doDialog";
    
    // preferences
    public static final String SHARED_PREFS = "WiglePrefs";
    public static final String PREF_USERNAME = "username";
    public static final String PREF_PASSWORD = "password";
    public static final String PREF_SHOW_CURRENT = "showCurrent";
    public static final String PREF_BE_ANONYMOUS = "beAnonymous";
    public static final String PREF_DONATE = "donate";
    public static final String PREF_DB_MARKER = "dbMarker";
    public static final String PREF_MAX_DB = "maxDbMarker";
    public static final String PREF_NETS_UPLOADED = "netsUploaded";
    public static final String PREF_SCAN_PERIOD_STILL = "scanPeriodStill";
    public static final String PREF_SCAN_PERIOD = "scanPeriod";
    public static final String PREF_SCAN_PERIOD_FAST = "scanPeriodFast";
    public static final String GPS_SCAN_PERIOD = "gpsPeriod";
    public static final String PREF_FOUND_SOUND = "foundSound";
    public static final String PREF_FOUND_NEW_SOUND = "foundNewSound";
    public static final String PREF_SPEECH_PERIOD = "speechPeriod";
    public static final String PREF_LANGUAGE = "speechLanguage";
    public static final String PREF_RESET_WIFI_PERIOD = "resetWifiPeriod";
    public static final String PREF_BATTERY_KILL_PERCENT = "batteryKillPercent";    
    public static final String PREF_SPEECH_GPS = "speechGPS";
    public static final String PREF_MUTED = "muted";
    public static final String PREF_WIFI_WAS_OFF = "wifiWasOff";
    public static final String PREF_DISTANCE_RUN = "distRun";
    public static final String PREF_DISTANCE_TOTAL = "distTotal";
    public static final String PREF_DISTANCE_PREV_RUN = "distPrevRun";
    public static final String PREF_MAP_ONLY_NEWDB = "mapOnlyNewDB";
    public static final String PREF_PREV_LAT = "prevLat";
    public static final String PREF_PREV_LON = "prevLon";
    public static final String PREF_PREV_ZOOM = "prevZoom";
    public static final String PREF_LIST_SORT = "listSort";
    public static final String PREF_SCAN_RUNNING = "scanRunning";
    public static final String PREF_METRIC = "metric";
    public static final String PREF_MAP_LABEL = "mapLabel";
    public static final String PREF_CIRCLE_SIZE_MAP = "circleSizeMap";
    public static final String PREF_USE_NETWORK_LOC = "useNetworkLoc";    
    
    // what to speak on announcements
    public static final String PREF_SPEAK_RUN = "speakRun";
    public static final String PREF_SPEAK_NEW_WIFI = "speakNew";
    public static final String PREF_SPEAK_NEW_CELL = "speakNewCell";
    public static final String PREF_SPEAK_QUEUE = "speakQueue";
    public static final String PREF_SPEAK_MILES = "speakMiles";
    public static final String PREF_SPEAK_TIME = "speakTime";
    public static final String PREF_SPEAK_BATTERY = "speakBattery";
    public static final String PREF_SPEAK_SSID = "speakSsid";
    public static final String PREF_SPEAK_WIFI_RESTART = "speakWifiRestart";    
    
    // map ssid filter
    public static final String PREF_MAPF_REGEX = "mapfRegex";
    public static final String PREF_MAPF_INVERT = "mapfInvert";
    public static final String PREF_MAPF_OPEN = "mapfOpen";
    public static final String PREF_MAPF_WEP = "mapfWep";
    public static final String PREF_MAPF_WPA = "mapfWpa";
    public static final String PREF_MAPF_CELL = "mapfCell";    
    public static final String PREF_MAPF_ENABLED = "mapfEnabled";
    public static final String FILTER_PREF_PREFIX = "LA";
    
    public static final String NETWORK_EXTRA_BSSID = "extraBssid";
    
    public static final long DEFAULT_SPEECH_PERIOD = 60L;
    public static final long DEFAULT_RESET_WIFI_PERIOD = 90000L;    
    public static final long LOCATION_UPDATE_INTERVAL = 1000L;
    public static final long SCAN_STILL_DEFAULT = 3000L;
    public static final long SCAN_DEFAULT = 2000L;
    public static final long SCAN_FAST_DEFAULT = 1000L;
    public static final long DEFAULT_BATTERY_KILL_PERCENT = 2L;    
    
    public static final String ANONYMOUS = "anonymous";
    private static final String WIFI_LOCK_NAME = "wigleWifiLock";
    //static final String THREAD_DEATH_MESSAGE = "threadDeathMessage";
    static final boolean DEBUG = false;
    
    /** cross-activity communication */
    public static class TrailStat {
      public int newWifiForRun = 0;
      public int newWifiForDB = 0;
      public int newCellForRun = 0;
      public int newCellForDB = 0;
    }
    public static class LameStatic {
      public Location location; 
      public ConcurrentLinkedHashMap<GeoPoint,TrailStat> trail = 
        new ConcurrentLinkedHashMap<GeoPoint,TrailStat>( 512 );
      public int runNets;
      public long newNets;
      public long newWifi;
      public long newCells;
      public int currNets;
      public int preQueueSize;
      public long dbNets;
      public long dbLocs;
      public DatabaseHelper dbHelper;
      public Set<String> runNetworks;
      public QueryArgs queryArgs;
    }
    public static final LameStatic lameStatic = new LameStatic();
    
    // cache
    private static final ThreadLocal<ConcurrentLinkedHashMap<String,Network>> networkCache = 
      new ThreadLocal<ConcurrentLinkedHashMap<String,Network>>() {
        protected ConcurrentLinkedHashMap<String,Network> initialValue() {
            return new ConcurrentLinkedHashMap<String,Network>( 128 );
        }
    };
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate( final Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        // set language
        MainActivity.setLocale( this );
        setContentView( R.layout.list );
        
        if ( DEBUG ) {
          Debug.startMethodTracing("wigle");
        }
        
        // set ourselves for later finishing by other activities
        MainActivity main = MainActivity.getMainActivity( this );
        if ( main != null ) {
          main.setListActivity( this );
        }
        
        // do some of our own error handling, write a file with the stack
        final UncaughtExceptionHandler origHandler = Thread.getDefaultUncaughtExceptionHandler();
        if ( ! (origHandler instanceof WigleUncaughtExceptionHandler) ) {
          Thread.setDefaultUncaughtExceptionHandler( 
              new WigleUncaughtExceptionHandler( this.getApplicationContext(), origHandler ) ); 
        }
        
        // test the error reporting
        // if( true ){ throw new RuntimeException( "weee" ); }
        
        final Object stored = getLastNonConfigurationInstance();
        if ( stored != null && stored instanceof State ) {
          // pry an orientation change, which calls destroy, but we set this in onRetainNonConfigurationInstance
          state = (State) stored;
          
          // tell those that need it that we have a new context
          state.gpsListener.setListActivity( this );
          state.wifiReceiver.setListActivity( this );
          if ( state.fileUploaderTask != null ) {
            state.fileUploaderTask.setContext( this );
          }
        }
        else {
          state = new State();
          state.finishing = new AtomicBoolean( false );
          state.transferring = new AtomicBoolean( false );
          
          // new run, reset
          final SharedPreferences prefs = this.getSharedPreferences( SHARED_PREFS, 0 );
          final float prevRun = prefs.getFloat( PREF_DISTANCE_RUN, 0f );
          Editor edit = prefs.edit();
          edit.putFloat( PREF_DISTANCE_RUN, 0f );
          edit.putFloat( PREF_DISTANCE_PREV_RUN, prevRun );
          edit.commit();
        }
        
        final String id = Settings.Secure.getString( getContentResolver(), Settings.Secure.ANDROID_ID );

        // DO NOT turn these into |=, they will cause older dalvik verifiers to freak out
        state.inEmulator = id == null;
        state.inEmulator =  state.inEmulator || "sdk".equals( android.os.Build.PRODUCT );
        state.inEmulator = state.inEmulator || "google_sdk".equals( android.os.Build.PRODUCT );

        info( "id: '" + id + "' inEmulator: " + state.inEmulator + " product: " + android.os.Build.PRODUCT );
        info( "android release: '" + Build.VERSION.RELEASE + "' debug: " + DEBUG );
        
        if ( state.numberFormat0 == null ) {
          state.numberFormat0 = NumberFormat.getNumberInstance( Locale.US );
          if ( state.numberFormat0 instanceof DecimalFormat ) {
            ((DecimalFormat) state.numberFormat0).setMaximumFractionDigits( 0 );
          }
        }
        
        if ( state.numberFormat1 == null ) {
          state.numberFormat1 = NumberFormat.getNumberInstance( Locale.US );
          if ( state.numberFormat1 instanceof DecimalFormat ) {
            ((DecimalFormat) state.numberFormat1).setMaximumFractionDigits( 1 );
          }
        }
        
        if ( state.numberFormat8 == null ) {
          state.numberFormat8 = NumberFormat.getNumberInstance( Locale.US );
          if ( state.numberFormat8 instanceof DecimalFormat ) {
            ((DecimalFormat) state.numberFormat8).setMaximumFractionDigits( 8 );
          }
        }
        
        info( "setupService" );
        setupService();
        info( "setupDatabase" );
        setupDatabase();
        info( "setupUploadButton" );
        setupUploadButton();
        info( "setupList" );
        setupList();
        info( "setupSound" );
        setupSound();
        info( "setupWifi" );
        setupWifi();
        info( "setupLocation" );
        setupLocation();
        info( "setupBattery" );
        setupBattery();
        info( "setNetCountUI" );
        setNetCountUI();
        info( "setStatusUI" );
        setStatusUI( (String) null );
        info( "setup complete" );
    }
    
    public void setNetCountUI() {
      TextView tv = (TextView) findViewById( R.id.stats_run );
      tv.setText( getString(R.string.run) + ": " + state.wifiReceiver.getRunNetworkCount() );
      tv = (TextView) findViewById( R.id.stats_new );
      tv.setText( getString(R.string.new_word) + ": " + state.dbHelper.getNewNetworkCount() );
      tv = (TextView) findViewById( R.id.stats_dbnets );
      tv.setText( getString(R.string.db) + ": " + state.dbHelper.getNetworkCount() );
    }
    
    public void setStatusUI( String status ) {
      if ( status == null ) {
        status = previousStatus;
      }
      if ( status != null ) {
        // keep around a previous, for orientation changes
        previousStatus = status;
        final TextView tv = (TextView) findViewById( R.id.status );
        tv.setText( status );
      }
    }
    
    public boolean inEmulator() {
      return state.inEmulator;
    }
    
    public DatabaseHelper getDBHelper() {
      return state.dbHelper;
    }
    
    public BatteryLevelReceiver getBatteryLevelReceiver() {
      return state.batteryLevelReceiver;
    }
    
    public GPSListener getGPSListener() {
      return state.gpsListener;
    }
    
    public PhoneState getPhoneState() {
      return state.phoneState;
    }
    
    public boolean isFinishing() {
      return state.finishing.get();
    }
    
    public boolean isTransferring() {
      return state.transferring.get();
    }
    
    public boolean isScanning() {
      return isScanning(this);
    }
    
    public static boolean isScanning(final Context context) {
      final SharedPreferences prefs = context.getSharedPreferences( SHARED_PREFS, 0 );
      return prefs.getBoolean( PREF_SCAN_RUNNING, true );
    }
    
    public void playNewNetSound() {
      try {
        if ( state.soundNewPop != null && ! state.soundNewPop.isPlaying() ) {
          // play sound on something new
          state.soundNewPop.start();
        }
        else {
          ListActivity.info( "soundNewPop is playing or null" );
        }
      }
      catch ( IllegalStateException ex ) {
        // ohwell, likely already playing
        info( "exception trying to play sound: " + ex );
      }
    }
    
    public void playRunNetSound() {
      try {
        if ( state.soundPop != null && ! state.soundPop.isPlaying() ) {
          // play sound on something new
          state.soundPop.start();
        }  
        else {
          ListActivity.info( "soundPop is playing or null" );
        }
      }
      catch ( IllegalStateException ex ) {
        // ohwell, likely already playing
        info( "exception trying to play sound: " + ex );
      }
    }
    
    @Override
    public Object onRetainNonConfigurationInstance() {
      info( "onRetainNonConfigurationInstance" );
      // return the whole state class to copy data from
      return state;
    }
    
    @Override
    public void onPause() {
      info( "LIST: paused. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onPause();
    }
    
    @Override
    public void onResume() {
      info( "LIST: resumed. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onResume();
    }
    
    @Override
    public void onStart() {
      info( "LIST: start. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onStart();
    }
    
    @Override
    public void onStop() {
      info( "LIST: stop. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onStop();
    }

    @Override
    public void onRestart() {
      info( "LIST: restart. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onRestart();
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
      if (keyCode == KeyEvent.KEYCODE_BACK) {
        info( "onKeyDown: treating back like home, not quitting app" );
        moveTaskToBack(true);
        if ( getParent() != null ) {
          getParent().moveTaskToBack( true );
        }
        return true;
      }
      return super.onKeyDown(keyCode, event);
    }
    
    @Override
    public void onDestroy() {
      info( "LIST: destroy. networks: " + state.wifiReceiver.getRunNetworkCount() );
      super.onDestroy();
    }
    
    @Override
    public void finish() {
      info( "LIST: finish. networks: " + state.wifiReceiver.getRunNetworkCount() );
      
      final boolean wasFinishing = state.finishing.getAndSet( true );
      if ( wasFinishing ) {
        info( "LIST: finish called twice!" );
      }

      // save our location for later runs
      state.gpsListener.saveLocation();
      
      // close the db. not in destroy, because it'll still write after that.
      state.dbHelper.close();
      
      final LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
      if ( state.gpsListener != null ) {
        locationManager.removeGpsStatusListener( state.gpsListener );
        locationManager.removeUpdates( state.gpsListener );
      }
      
      try {
        this.unregisterReceiver( state.wifiReceiver );
      }
      catch ( final IllegalArgumentException ex ) {
        info( "wifiReceiver not registered: " + ex );
      }

      // stop the service, so when we die it's both stopped and unbound and will die
      final Intent serviceIntent = new Intent( this, WigleService.class );
      this.stopService( serviceIntent );
      try {
        // have to use the app context to bind to the service, cuz we're in tabs
        getApplicationContext().unbindService( state.serviceConnection );
      }
      catch ( final IllegalArgumentException ex ) {
        info( "serviceConnection not registered: " + ex, ex );
      }    
      
      // release the lock before turning wifi off
      if ( state.wifiLock != null && state.wifiLock.isHeld() ) {
        try {
          state.wifiLock.release();
        }
        catch ( Exception ex ) {
          error( "exception releasing wifi lock: " + ex, ex );
        }
      }
      
      final SharedPreferences prefs = this.getSharedPreferences( SHARED_PREFS, 0 );
      final boolean wifiWasOff = prefs.getBoolean( PREF_WIFI_WAS_OFF, false );
      // don't call on emulator, it crashes it
      if ( wifiWasOff && ! state.inEmulator ) {
        // tell user, cuz this takes a little while
        Toast.makeText( this, getString(R.string.turning_wifi_off), Toast.LENGTH_SHORT ).show();
        
        // well turn it of now that we're done
        final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        info( "turning back off wifi" );
        wifiManager.setWifiEnabled( false );
      }
      
      TelephonyManager tele = (TelephonyManager) getSystemService( TELEPHONY_SERVICE );
      if ( tele != null && state.phoneState != null ) {
        tele.listen( state.phoneState, PhoneStateListener.LISTEN_NONE );
      }
      
      if ( state.tts != null ) {
        if ( ! isMuted() ) {
          // give time for the above "done" to be said
          sleep( 250 );
        }
        state.tts.shutdown();
      }
      
      
      if ( DEBUG ) {
        Debug.stopMethodTracing();
      }

      // clean up.
      if ( state.soundPop != null ) {
        state.soundPop.release();
      }
      if ( state.soundNewPop != null ) {
        state.soundNewPop.release();
      }
      
      super.finish();
    }
    
    /* Creates the menu items */
    @Override
    public boolean onCreateOptionsMenu( final Menu menu ) {
      MenuItem item = menu.add(0, MENU_SORT, 0, getString(R.string.menu_sort));
      item.setIcon( android.R.drawable.ic_menu_sort_alphabetically );
      
      final String scan = isScanning() ? getString(R.string.off) : getString(R.string.on);
      item = menu.add(0, MENU_SCAN, 0, getString(R.string.scan) + " " + scan);
      item.setIcon( isScanning() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play );      
      
      final String wake = MainActivity.isScreenLocked( this ) ? 
          getString(R.string.menu_screen_sleep) : getString(R.string.menu_screen_wake);
      item = menu.add(0, MENU_WAKELOCK, 0, wake);
      item.setIcon( android.R.drawable.ic_menu_gallery );
      
      item = menu.add(0, MENU_EXIT, 0, getString(R.string.menu_exit));
      item.setIcon( android.R.drawable.ic_menu_close_clear_cancel );
      
      item = menu.add(0, MENU_FILTER, 0, getString(R.string.menu_ssid_filter));
      item.setIcon( android.R.drawable.ic_menu_search );
              
      item = menu.add(0, MENU_SETTINGS, 0, getString(R.string.menu_settings));
      item.setIcon( android.R.drawable.ic_menu_preferences );
        
      return true;
    }

    /* Handles item selections */
    @Override
    public boolean onOptionsItemSelected( final MenuItem item ) {
        switch ( item.getItemId() ) {
          case MENU_SETTINGS: {
            info("start settings activity");
            final Intent settingsIntent = new Intent( this, SettingsActivity.class );
            startActivity( settingsIntent );
            break;
          }
          case MENU_WAKELOCK: {
            boolean screenLocked = ! MainActivity.isScreenLocked( this );
            MainActivity.setLockScreen( this, screenLocked );
            final String wake = screenLocked ? getString(R.string.menu_screen_sleep) : getString(R.string.menu_screen_wake);
            item.setTitle( wake );
            return true;
          }
          case MENU_SORT: {
            info("sort dialog");
            showDialog( SORT_DIALOG );
            return true;
          }
          case MENU_SCAN: {
            boolean scanning = ! isScanning();
            final Editor edit = this.getSharedPreferences( SHARED_PREFS, 0 ).edit();
            edit.putBoolean(PREF_SCAN_RUNNING, scanning);
            edit.commit();
            String name = getString(R.string.scan) + " " + (scanning ? getString(R.string.off) : getString(R.string.on));
            item.setTitle( name );
            item.setIcon( isScanning() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play );
            handleScanChange();
            return true;
          }
          case MENU_EXIT:
            // call over to finish
            finish();
            return true;
          case MENU_FILTER:
            showDialog( SSID_FILTER );
            return true;          
        }        
        return false;
    }
    
    private void handleScanChange() {
      final boolean isScanning = isScanning();
      info("handleScanChange: isScanning now: " + isScanning );
      if ( isScanning ) {
        // turn on location updates
        this.setLocationUpdates(LOCATION_UPDATE_INTERVAL, 0f);
        setStatusUI( "Scanning Turned On" );
        if ( ! state.wifiLock.isHeld() ){
          state.wifiLock.acquire();
        }
      }
      else {
        // turn off location updates
        this.setLocationUpdates(0L, 0f);
        setStatusUI( "Scanning Turned Off" );
        state.gpsListener.handleScanStop();
        if ( state.wifiLock.isHeld() ){
          try {
            state.wifiLock.release();
          }
          catch (SecurityException ex) {
            // a case where we have a leftover lock from another run?
            info("exception releasing wifilock: " + ex);
          }
        }
      }
    }
    
    @Override
    public Dialog onCreateDialog( int which ) {
      switch ( which ) {
        case SSID_FILTER:
          return MappingActivity.createSsidFilterDialog(this, FILTER_PREF_PREFIX);
        case SORT_DIALOG:
          final Dialog dialog = new Dialog( this );
  
          dialog.setContentView( R.layout.listdialog );
          dialog.setTitle( getString(R.string.sort_title) );
  
          TextView text = (TextView) dialog.findViewById( R.id.text );
          text.setText( getString(R.string.sort_spin_label) );
          
          final SharedPreferences prefs = getSharedPreferences( SHARED_PREFS, 0 );
          final Editor editor = prefs.edit();
          
          Spinner spinner = (Spinner) dialog.findViewById( R.id.sort_spinner );
          ArrayAdapter<String> adapter = new ArrayAdapter<String>(
              this, android.R.layout.simple_spinner_item);
          final int[] listSorts = new int[]{ WifiReceiver.CHANNEL_COMPARE, WifiReceiver.CRYPTO_COMPARE,
              WifiReceiver.FIND_TIME_COMPARE, WifiReceiver.SIGNAL_COMPARE, WifiReceiver.SSID_COMPARE };
          final String[] listSortName = new String[]{ getString(R.string.channel),getString(R.string.crypto),
              getString(R.string.found_time),getString(R.string.signal),getString(R.string.ssid) };
          int listSort = prefs.getInt( PREF_LIST_SORT, WifiReceiver.SIGNAL_COMPARE );
          int periodIndex = 0;
          for ( int i = 0; i < listSorts.length; i++ ) {
            adapter.add( listSortName[i] );
            if ( listSort == listSorts[i] ) {
              periodIndex = i;
            }
          }
          adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
          spinner.setAdapter( adapter );
          spinner.setSelection( periodIndex );
          spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
            public void onItemSelected( final AdapterView<?> parent, final View v, final int position, final long id ) {
              // set pref
              final int listSort = listSorts[position];
              ListActivity.info( PREF_LIST_SORT + " setting list sort: " + listSort );
              editor.putInt( PREF_LIST_SORT, listSort );
              editor.commit();
            }
            public void onNothingSelected( final AdapterView<?> arg0 ) {}
            });
          
          Button ok = (Button) dialog.findViewById( R.id.listdialog_button );
          ok.setOnClickListener( new OnClickListener() {
              public void onClick( final View buttonView ) {  
                try {
                  dialog.dismiss();
                }
                catch ( Exception ex ) {
                  // guess it wasn't there anyways
                  info( "exception dismissing sort dialog: " + ex );
                }
              }
            } );
          
          return dialog;
        default:
          error( "unhandled dialog: " + which );
      }
      return null;
    }

    // why is this even here? this is retarded. via:
    // http://stackoverflow.com/questions/456211/activity-restart-on-rotation-android
    @Override
    public void onConfigurationChanged( final Configuration newConfig ) {
      info( "LIST: on config change" );
      MainActivity.setLocale( this, newConfig);
      super.onConfigurationChanged( newConfig );
      setContentView( R.layout.list );      
      
      // have to redo linkages/listeners
      setupUploadButton();
      setupMuteButton();
      setupList();
      state.wifiReceiver.setListAdapter( listAdapter );
      setNetCountUI();
      setLocationUI();
      setStatusUI( previousStatus );
    }
    
    private void setupDatabase() {
      // could be set by nonconfig retain
      if ( state.dbHelper == null ) {
        state.dbHelper = new DatabaseHelper( this.getApplicationContext() );
        //state.dbHelper.checkDB();
        state.dbHelper.start();
        lameStatic.dbHelper = state.dbHelper;
      }      
    }
    
    private void setupList() {
      // not set by nonconfig retain
      listAdapter = new NetworkListAdapter( getApplicationContext(), R.layout.row );
      setupListAdapter( this, listAdapter, R.id.ListView01 );
    }
     
    public static void setupListAdapter( final Activity activity, final NetworkListAdapter listAdapter, final int id) {
      final ListView listView = (ListView) activity.findViewById( id );
      listView.setAdapter( listAdapter ); 
      listView.setOnItemClickListener( new AdapterView.OnItemClickListener() {
        public void onItemClick( AdapterView<?> parent, View view, final int position, final long id ) {
          final Network network = (Network) parent.getItemAtPosition( position );
          ListActivity.getNetworkCache().put( network.getBssid(), network );
          final Intent intent = new Intent( activity, NetworkActivity.class );
          intent.putExtra( NETWORK_EXTRA_BSSID, network.getBssid() );
          activity.startActivity( intent );
        }
      });
    }
    
    private void setupWifi() {
      // warn about turning off network notification
      final String notifOn = Settings.Secure.getString(getContentResolver(), 
          Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON );
      if ( notifOn != null && "1".equals( notifOn ) && state.wifiReceiver == null ) {
        Toast.makeText( this, getString(R.string.best_results), 
            Toast.LENGTH_LONG ).show();
      }
    
      final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
      final SharedPreferences prefs = this.getSharedPreferences( SHARED_PREFS, 0 );
      final Editor edit = prefs.edit();
      
      // keep track of for later
      boolean turnedWifiOn = false;
      if ( ! wifiManager.isWifiEnabled() ) {
        // tell user, cuz this takes a little while
        Toast.makeText( this, getString(R.string.turn_on_wifi), Toast.LENGTH_LONG ).show();
        
        // save so we can turn it back off when we exit  
        edit.putBoolean( PREF_WIFI_WAS_OFF, true );
        
        // just turn it on, but not in emulator cuz it crashes it
        if ( ! state.inEmulator ) {
          info( "turning on wifi");
          wifiManager.setWifiEnabled( true );
          info( "wifi on");
          turnedWifiOn = true;
        }
      }
      else {
        edit.putBoolean( PREF_WIFI_WAS_OFF, false );
      }
      edit.commit();
      
      if ( state.wifiReceiver == null ) {
        info( "new wifiReceiver");
        // wifi scan listener
        // this receiver is the main workhorse of the entire app
        state.wifiReceiver = new WifiReceiver( this, state.dbHelper, listAdapter );
        state.wifiReceiver.setupWifiTimer( turnedWifiOn );
        
        // register
        info( "register BroadcastReceiver");
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction( WifiManager.SCAN_RESULTS_AVAILABLE_ACTION );
        this.registerReceiver( state.wifiReceiver, intentFilter );
      }
      // always set our current list adapter
      state.wifiReceiver.setListAdapter( listAdapter );
      
      if ( state.wifiLock == null ) {
        info( "lock wifi radio on");
        // lock the radio on
        state.wifiLock = wifiManager.createWifiLock( WifiManager.WIFI_MODE_SCAN_ONLY, WIFI_LOCK_NAME );
        state.wifiLock.acquire();
      }
    }
    
    /**
     * Computes the battery level by registering a receiver to the intent triggered 
     * by a battery status/level change.
     */
    private void setupBattery() {
      if ( state.batteryLevelReceiver == null ) {
        state.batteryLevelReceiver = new BatteryLevelReceiver();
        IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(state.batteryLevelReceiver, batteryLevelFilter);
      }
    }
    
    public void setTransferring() {
      state.transferring.set( true );
    }
    
    /**
     * FileUploaderListener interface
     */
    public void transferComplete() {
      state.transferring.set( false );
      info( "transfer complete" );
      // start a scan to get the ball rolling again if this is non-stop mode
      scheduleScan();
      state.fileUploaderTask = null;
    }
    
    public void scheduleScan() {
      state.wifiReceiver.scheduleScan();
    }
    
    public void speak( final String string ) {
      if ( ! isMuted() && state.tts != null ) {
        state.tts.speak( string );
      }
    }
    
    public void interruptSpeak() {
      if ( state.tts != null ) {
        state.tts.stop();
      }
    }
    
    private void setupLocation() {
      // set on UI if we already have one
      setLocationUI();
      
      final LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
      
      // check if there is a gps
      final LocationProvider locProvider = locationManager.getProvider( GPS_PROVIDER );
      if ( locProvider == null ) {
        Toast.makeText( this, getString(R.string.no_gps_device), Toast.LENGTH_LONG ).show();
      }
      else if ( ! locationManager.isProviderEnabled( GPS_PROVIDER ) ) {
        // gps exists, but isn't on
        Toast.makeText( this, getString(R.string.turn_on_gps), Toast.LENGTH_SHORT ).show();
        final Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS );
        try {
          startActivity(myIntent);
        }
        catch (Exception ex) {
          error("exception trying to start location activity: " + ex, ex);
        }
      }
      // emulator crashes if you ask this
      if ( ! state.inEmulator && ! locationManager.isProviderEnabled( NETWORK_PROVIDER ) && state.gpsListener == null ) {
        //Toast.makeText( this, "For best results, set \"Use wireless networks\" in \"Location & security\"", 
        //    Toast.LENGTH_LONG ).show();
      }

      if ( state.gpsListener == null ) {
        // force a listener to be created
        handleScanChange();
      }
    }
    
    public long getLocationSetPeriod() {
      final SharedPreferences prefs = getSharedPreferences( ListActivity.SHARED_PREFS, 0 );
      final long prefPeriod = prefs.getLong(ListActivity.GPS_SCAN_PERIOD, ListActivity.LOCATION_UPDATE_INTERVAL);
      long setPeriod = prefPeriod;
      if (setPeriod == 0 ){
        setPeriod = Math.max(state.wifiReceiver.getScanPeriod(), ListActivity.LOCATION_UPDATE_INTERVAL); 
      }
      return setPeriod;
    }
    
    public void setLocationUpdates() {
      final long setPeriod = getLocationSetPeriod();    
      setLocationUpdates(setPeriod, 0f);
    }    
    
    /**
     * resets the gps listener to the requested update time and distance.
     * an updateIntervalMillis of <= 0 will not register for updates. 
     */
    public void setLocationUpdates(final long updateIntervalMillis, final float updateMeters) {
      final LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
      
      if ( state.gpsListener != null ) {
        // remove any old requests
        locationManager.removeUpdates( state.gpsListener );
        locationManager.removeGpsStatusListener( state.gpsListener );
      }
      
      // create a new listener to try and get around the gps stopping bug
      state.gpsListener = new GPSListener( this );
      state.gpsListener.setMapListener(MappingActivity.STATIC_LOCATION_LISTENER);
      locationManager.addGpsStatusListener( state.gpsListener );      
      
      final SharedPreferences prefs = getSharedPreferences( ListActivity.SHARED_PREFS, 0 );
      final boolean useNetworkLoc = prefs.getBoolean(ListActivity.PREF_USE_NETWORK_LOC, false);

      final List<String> providers = locationManager.getAllProviders();
      if (providers != null) {
        for ( String provider : providers ) {
          info( "available provider: " + provider + " updateIntervalMillis: " + updateIntervalMillis );
          if ( ! useNetworkLoc && LocationManager.NETWORK_PROVIDER.equals(provider)) {
            // skip!          
            continue;
          }
          if ( ! "passive".equals( provider ) && updateIntervalMillis > 0 ) {
            info("using provider: " + provider);
            locationManager.requestLocationUpdates( provider, updateIntervalMillis, updateMeters, state.gpsListener );
          }
        }
      }
    }
    
    public void setLocationUI() {
      if ( state.gpsListener == null ) {
        return;
      }
      
      try {       
        TextView tv = (TextView) this.findViewById( R.id.LocationTextView06 );
        tv.setText( getString(R.string.list_short_sats) + " " + state.gpsListener.getSatCount() );
        
        final Location location = state.gpsListener.getLocation();
        
        tv = (TextView) this.findViewById( R.id.LocationTextView01 );
        String latText = "";
        if ( location == null ) {
          if ( isScanning() ) {
            latText = getString(R.string.list_waiting_gps);
          }
          else {
            latText = getString(R.string.list_scanning_off);
          }
        }
        else {
          latText = state.numberFormat8.format( location.getLatitude() );
        }
        tv.setText( getString(R.string.list_short_lat) + " " + latText );
        
        tv = (TextView) this.findViewById( R.id.LocationTextView02 );
        tv.setText( getString(R.string.list_short_lon) + " " + (location == null ? "" : state.numberFormat8.format( location.getLongitude() ) ) );
        
        tv = (TextView) this.findViewById( R.id.LocationTextView03 );
        tv.setText( getString(R.string.list_speed) + " " + (location == null ? "" : metersPerSecondToSpeedString(state.numberFormat1, this, location.getSpeed()) ) );
        
        TextView tv4 = (TextView) this.findViewById( R.id.LocationTextView04 );
        TextView tv5 = (TextView) this.findViewById( R.id.LocationTextView05 );
        if ( location == null ) {
          tv4.setText( "" );
          tv5.setText( "" );
        }
        else {
          String distString = DashboardActivity.metersToString( 
              state.numberFormat0, this, location.getAccuracy(), true );
          tv4.setText( "+/- " + distString );
          distString = DashboardActivity.metersToString( 
              state.numberFormat0, this, (float) location.getAltitude(), true );
          tv5.setText( getString(R.string.list_short_alt) + " " + distString );
        }
      }
      catch ( IncompatibleClassChangeError ex ) {
        // yeah, saw this in the wild, who knows.
        error( "wierd ex: " + ex, ex);
      }
    }
    
    public static String metersPerSecondToSpeedString( final NumberFormat numberFormat, final Context context,
        final float metersPerSecond ) {
      
      final SharedPreferences prefs = context.getSharedPreferences( ListActivity.SHARED_PREFS, 0 );
      final boolean metric = prefs.getBoolean( ListActivity.PREF_METRIC, false );
      
      String retval = null;
      if ( metric ) {
        retval = numberFormat.format( metersPerSecond * 3.6 ) + " " + context.getString(R.string.kmph);
      }
      else {
        retval = numberFormat.format( metersPerSecond * 2.23693629f ) + " " + context.getString(R.string.mph);
      }
      return retval;
    }
    
    private void setupUploadButton() {
      final Button button = (Button) findViewById( R.id.upload_button );
      button.setOnClickListener( new OnClickListener() { 
          public void onClick( final View view ) {
            final MainActivity main = MainActivity.getMainActivity( ListActivity.this );
            final SharedPreferences prefs = main.getSharedPreferences( ListActivity.SHARED_PREFS, 0 );
            final String username = prefs.getString( ListActivity.PREF_USERNAME, "anonymous" );
            final String text = getString(R.string.list_upload) + "\n" + getString(R.string.username) + ": " + username;
            MainActivity.createConfirmation( ListActivity.this, text, new Doer() {
              @Override
              public void execute() {                
                setTransferring();
                uploadFile( state.dbHelper );
              }
            } );
          }
        });
    }
    
    private void setupService() {
      // could be set by nonconfig retain
      if ( state.serviceConnection == null ) {        
        final Intent serviceIntent = new Intent( this.getApplicationContext(), WigleService.class );
        final ComponentName compName = startService( serviceIntent );
        if ( compName == null ) {
          error( "startService() failed!" );
        }
        else {
          info( "service started ok: " + compName );
        }
        
        state.serviceConnection = new ServiceConnection() {
          public void onServiceConnected( final ComponentName name, final IBinder iBinder ) {
            info( name + " service connected" ); 
          }
          public void onServiceDisconnected( final ComponentName name ) {
            info( name + " service disconnected" );
          }
        };  
      
        int flags = 0;
        // have to use the app context to bind to the service, cuz we're in tabs
        // http://code.google.com/p/android/issues/detail?id=2483#c2
        final boolean bound = getApplicationContext().bindService( serviceIntent, state.serviceConnection, flags );
        info( "service bound: " + bound );        
      }
    }
    
    private void setupSound() {
      // could have been retained
      if ( state.soundPop == null ) {
        state.soundPop = createMediaPlayer( R.raw.pop );
      }
      if ( state.soundNewPop == null ) {
        state.soundNewPop = createMediaPlayer( R.raw.newpop );
      }

      // make volume change "media"
      this.setVolumeControlStream( AudioManager.STREAM_MUSIC );  

      try {
        if ( TTS.hasTTS() ) {
          // don't reuse an old one, has to be on *this* context
          if ( state.tts != null ) {
            state.tts.shutdown();
          }
          // this has to have the parent activity, for whatever wacky reasons
          Activity context = this.getParent();
          if ( context == null ) {
            context = this;
          }
          state.tts = new TTS( context );        
        }
      }
      catch ( Exception ex ) {
        error( "exception setting TTS: " + ex, ex);
      }
      
      TelephonyManager tele = (TelephonyManager) getSystemService( TELEPHONY_SERVICE );
      if ( tele != null && state.phoneState == null ) {
        state.phoneState = PhoneStateFactory.createPhoneState();
        final int signal_strengths = 256;
        try {
          tele.listen( state.phoneState, PhoneStateListener.LISTEN_SERVICE_STATE
            | PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_SIGNAL_STRENGTH | signal_strengths );
        }
        catch (SecurityException ex) {
          info("cannot get call state, will play audio over any telephone calls: " + ex);
        }
      }
      
      setupMuteButton();
    }
     
    private void setupMuteButton() {
      final Button mute = (Button) this.findViewById(R.id.mute);
      final SharedPreferences prefs = this.getSharedPreferences(SHARED_PREFS, 0);
      final boolean muted = prefs.getBoolean(PREF_MUTED, false);
      mute.setText(getString(muted ? R.string.play : R.string.mute));
      
      mute.setOnClickListener(new OnClickListener(){
        public void onClick( final View buttonView ) {
          boolean muted = prefs.getBoolean(PREF_MUTED, false);
          muted = ! muted;
          Editor editor = prefs.edit();
          editor.putBoolean( PREF_MUTED, muted );
          editor.commit();
          
          if ( muted ) {
            mute.setText(getString(R.string.play));
            interruptSpeak();
          }
          else {
            mute.setText(getString(R.string.mute));
          }
        }
      });
    }

    /** 
     * create a mediaplayer for a given raw resource id.
     * @param soundId the R.raw. id for a given sound
     * @return the mediaplayer for soundId or null if it could not be created.
     */
    private MediaPlayer createMediaPlayer( final int soundId ) {
      final MediaPlayer sound = createMp( this.getApplicationContext(), soundId );
      if ( sound == null ) {
        info( "sound null from media player" );
        return null;
      }
      // try to figure out why sounds stops after a while
      sound.setOnErrorListener( new OnErrorListener() {
        public boolean onError( final MediaPlayer mp, final int what, final int extra ) {
          String whatString = null;
          switch ( what ) {
            case MediaPlayer.MEDIA_ERROR_UNKNOWN:
              whatString = "error unknown";
              break;
            case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
              whatString = "server died";
              break;
            default:
              whatString = "not defined";
          }
          info( "media player error \"" + whatString + "\" what: " + what
            + " extra: " + extra + " mp: " + mp );
          return false;
        }
      } );

      return sound;
    }

    /** 
     * externalize the file from a given resource id (if it dosen't already exist), write to our dir if there is one.
     * @param context the context to use
     * @param resid the resource id
     * @param name the file name to write out
     * @return the uri of a file containing resid's resource
     */
    private static Uri resToFile( final Context context, final int resid, final String name ) throws IOException {
        // throw it in our bag of fun.
        String openString = name;
        final boolean hasSD = hasSD();
        if ( hasSD ) {
            final String filepath = MainActivity.safeFilePath( Environment.getExternalStorageDirectory() ) + "/wiglewifi/";
            final File path = new File( filepath );
            path.mkdirs();
            openString = filepath + name;
        }

        final File f = new File( openString );
      
        // see if it exists already
        if ( ! f.exists() ) { 
            info( "causing " + MainActivity.safeFilePath( f ) + " to be made" );
            // make it happen:
            f.createNewFile();
            
            InputStream is = null;
            FileOutputStream fos = null;
            try {
                is = context.getResources().openRawResource( resid );
                if ( hasSD ) {
                    fos = new FileOutputStream( f );
                } else { 
                    // XXX: should this be using openString instead? baroo?
                    fos = context.openFileOutput( name, Context.MODE_WORLD_READABLE );
                }

                final byte[] buff = new byte[ 1024 ];
                int rv = -1;
                while( ( rv = is.read( buff ) ) > -1 ) {
                    fos.write( buff, 0, rv );
                }
            } finally {
                if ( fos != null ) {
                    fos.close();
                }
                if ( is != null ) {
                    is.close();
                }
            }
        }
        return Uri.fromFile( f );
    }

    /** 
     * create a media player (trying several paths if available)
     * @param context the context to use
     * @param resid the resource to use
     * @return the media player for resid (or null if it wasn't creatable)
     */
    private static MediaPlayer createMp( final Context context, final int resid ) {
        try {
            MediaPlayer mp = MediaPlayer.create( context, resid );
            // this can fail for many reasons, but android 1.6 on archos5 definitely hates creating from resource
            if ( mp == null ) {
                Uri sounduri;
                // XXX: find a better way? baroo.
                if ( resid == R.raw.pop ) {
                    sounduri = resToFile( context, resid, "pop.wav" );
                } else if ( resid == R.raw.newpop ) {
                    sounduri = resToFile( context, resid, "newpop.wav" );
                } else {
                    info( "unknown raw sound id:"+resid );
                    return null;
                }
                mp = MediaPlayer.create( context, sounduri );
                // may still end up null
            }

            return mp;
        } catch (IOException ex) {
            error("ioe create failed: " + ex, ex);
            // fall through
        } catch (IllegalArgumentException ex) {
            error("iae create failed: " + ex, ex);
           // fall through
        } catch (SecurityException ex) {
            error("se create failed: " + ex, ex);
            // fall through
        } catch ( Resources.NotFoundException ex ) {
            error("rnfe create failed("+resid+"): " + ex, ex );
        }
        return null;
    }
   
    public boolean isMuted() {
      if ( state.phoneState != null && state.phoneState.isPhoneActive() ) {
        // always be quiet when the phone is active
        return true;
      }
      boolean retval = this.getSharedPreferences(SHARED_PREFS, 0).getBoolean(PREF_MUTED, false);
      // info( "ismuted: " + retval );
      return retval;
    }
    
    private void uploadFile( final DatabaseHelper dbHelper ){
      info( "upload file" );
      // actually need this Activity context, for dialogs
      state.fileUploaderTask = new FileUploaderTask( this, dbHelper, this, false );
      state.fileUploaderTask.start();
    }
    
    public static void sleep( final long sleep ) {
      try {
        Thread.sleep( sleep );
      }
      catch ( final InterruptedException ex ) {
        // no worries
      }
    }
    public static void info( final String value ) {
      Log.i( LOG_TAG, Thread.currentThread().getName() + "] " + value );
    }
    public static void warn( final String value ) {
      Log.w( LOG_TAG, Thread.currentThread().getName() + "] " + value );
    }
    public static void error( final String value ) {
      Log.e( LOG_TAG, Thread.currentThread().getName() + "] " + value );
    }

    public static void info( final String value, final Throwable t ) {
      Log.i( LOG_TAG, Thread.currentThread().getName() + "] " + value, t );
    }
    public static void warn( final String value, final Throwable t ) {
      Log.w( LOG_TAG, Thread.currentThread().getName() + "] " + value, t );
    }
    public static void error( final String value, final Throwable t ) {
      Log.e( LOG_TAG, Thread.currentThread().getName() + "] " + value, t );
    }

    /**
     * get the per-thread network LRU cache
     * @return per-thread network cache
     */
    public static ConcurrentLinkedHashMap<String,Network> getNetworkCache() {
      return networkCache.get();
    }
    
    public static void writeError( final Thread thread, final Throwable throwable, final Context context ) {
      writeError(thread, throwable, context, null);
    }
    public static void writeError( final Thread thread, final Throwable throwable, final Context context, final String detail ) {
      try {
        final String error = "Thread: " + thread + " throwable: " + throwable;
        error( error, throwable );
        if ( hasSD() ) {
          File file = new File( MainActivity.safeFilePath( Environment.getExternalStorageDirectory() ) + "/wiglewifi/" );
          file.mkdirs();
          file = new File(MainActivity.safeFilePath( Environment.getExternalStorageDirectory() ) 
              + "/wiglewifi/" + ERROR_STACK_FILENAME + "_" + System.currentTimeMillis() + ".txt" );
          error( "Writing stackfile to: " + MainActivity.safeFilePath( file ) + "/" + file.getName() );
          if ( ! file.exists() ) {
            file.createNewFile();
          }
          final FileOutputStream fos = new FileOutputStream( file );
          
          try {
            final String baseErrorMessage = MainActivity.getBaseErrorMessage( throwable, false );
            StringBuilder builder = new StringBuilder( "WigleWifi error log - " );
            SimpleDateFormat format = new SimpleDateFormat();
            builder.append( format.format( new Date() ) ).append( "\n" );
            final PackageManager pm = context.getPackageManager();
            final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
            builder.append( "versionName: " ).append( pi.versionName ).append( "\n" );
            builder.append( "baseError: " ).append( baseErrorMessage ).append( "\n\n" );
            if (detail != null) {
              builder.append( "detail: " ).append( detail ).append( "\n" );
            }
            builder.append( "packageName: " ).append( pi.packageName ).append( "\n" );
            builder.append( "MODEL: " ).append( android.os.Build.MODEL ).append( "\n" );
            builder.append( "RELEASE: " ).append( android.os.Build.VERSION.RELEASE ).append( "\n" );
          
            builder.append( "BOARD: " ).append( android.os.Build.BOARD ).append( "\n" );
            builder.append( "BRAND: " ).append( android.os.Build.BRAND ).append( "\n" );
            // android 1.6 android.os.Build.CPU_ABI;
            builder.append( "DEVICE: " ).append( android.os.Build.DEVICE ).append( "\n" );
            builder.append( "DISPLAY: " ).append( android.os.Build.DISPLAY ).append( "\n" );
            builder.append( "FINGERPRINT: " ).append( android.os.Build.FINGERPRINT ).append( "\n" );
            builder.append( "HOST: " ).append( android.os.Build.HOST ).append( "\n" );
            builder.append( "ID: " ).append( android.os.Build.ID ).append( "\n" );
            // android 1.6: android.os.Build.MANUFACTURER;
            builder.append( "PRODUCT: " ).append( android.os.Build.PRODUCT ).append( "\n" );
            builder.append( "TAGS: " ).append( android.os.Build.TAGS ).append( "\n" );
            builder.append( "TIME: " ).append( android.os.Build.TIME ).append( "\n" );
            builder.append( "TYPE: " ).append( android.os.Build.TYPE ).append( "\n" );
            builder.append( "USER: " ).append( android.os.Build.USER ).append( "\n" );
            
            // write to file
            fos.write( builder.toString().getBytes( ENCODING ) );
          }
          catch ( Throwable er ) {
            // ohwell
            error( "error getting data for error: " + er, er );
          }
          
          fos.write( (error + "\n\n").getBytes( ENCODING ) );
          throwable.printStackTrace( new PrintWriter( new OutputStreamWriter( fos, "UTF-8" ) ) );
          fos.close();
        }
      }
      catch ( final Exception ex ) {
        error( "error logging error: " + ex, ex );
        ex.printStackTrace();
      }
    }
    
    public static boolean hasSD() {
      File sdCard = new File( MainActivity.safeFilePath( Environment.getExternalStorageDirectory() ) + "/" );
      return sdCard != null && sdCard.exists() && sdCard.isDirectory() && sdCard.canRead() && sdCard.canWrite();
    }            
}




Java Source Code List

net.wigle.wigleandroid.ConcurrentLinkedHashMap.java
net.wigle.wigleandroid.DBException.java
net.wigle.wigleandroid.DBResultActivity.java
net.wigle.wigleandroid.DashboardActivity.java
net.wigle.wigleandroid.DataActivity.java
net.wigle.wigleandroid.DatabaseHelper.java
net.wigle.wigleandroid.ErrorReportActivity.java
net.wigle.wigleandroid.LatLon.java
net.wigle.wigleandroid.ListActivity.java
net.wigle.wigleandroid.MainActivity.java
net.wigle.wigleandroid.MappingActivity.java
net.wigle.wigleandroid.NetworkActivity.java
net.wigle.wigleandroid.NetworkListAdapter.java
net.wigle.wigleandroid.NetworkType.java
net.wigle.wigleandroid.Network.java
net.wigle.wigleandroid.OpenStreetMapViewWrapper.java
net.wigle.wigleandroid.Pair.java
net.wigle.wigleandroid.QueryArgs.java
net.wigle.wigleandroid.QueryThread.java
net.wigle.wigleandroid.SSLConfigurator.java
net.wigle.wigleandroid.SettingsActivity.java
net.wigle.wigleandroid.SpeechActivity.java
net.wigle.wigleandroid.TTS.java
net.wigle.wigleandroid.WigleAndroid.java
net.wigle.wigleandroid.WigleService.java
net.wigle.wigleandroid.WigleUncaughtExceptionHandler.java
net.wigle.wigleandroid.background.AbstractBackgroundTask.java
net.wigle.wigleandroid.background.AlertSettable.java
net.wigle.wigleandroid.background.BackgroundGuiHandler.java
net.wigle.wigleandroid.background.FileUploaderListener.java
net.wigle.wigleandroid.background.FileUploaderTask.java
net.wigle.wigleandroid.background.HttpDownloader.java
net.wigle.wigleandroid.background.HttpFileUploader.java
net.wigle.wigleandroid.background.KmlWriter.java
net.wigle.wigleandroid.background.Status.java
net.wigle.wigleandroid.listener.BatteryLevelReceiver.java
net.wigle.wigleandroid.listener.GPSListener.java
net.wigle.wigleandroid.listener.PhoneState7.java
net.wigle.wigleandroid.listener.PhoneStateFactory.java
net.wigle.wigleandroid.listener.PhoneState.java
net.wigle.wigleandroid.listener.SsidSpeaker.java
net.wigle.wigleandroid.listener.WifiReceiver.java