Java tutorial
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.mozstumbler.service.stumblerthread; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Location; import android.net.wifi.ScanResult; import android.support.v4.content.LocalBroadcastManager; import android.telephony.TelephonyManager; import org.json.JSONException; import org.json.JSONObject; import org.mozilla.mozstumbler.service.AppGlobals; import org.mozilla.mozstumbler.service.core.logging.Log; import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageContract; import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager; import org.mozilla.mozstumbler.service.stumblerthread.datahandling.StumblerBundle; import org.mozilla.mozstumbler.service.stumblerthread.scanners.GPSScanner; import org.mozilla.mozstumbler.service.stumblerthread.scanners.WifiScanner; import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellInfo; import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner; import java.io.IOException; import java.util.List; import java.util.Map; public final class Reporter extends BroadcastReceiver implements IReporter { private static final String LOG_TAG = AppGlobals.LOG_PREFIX + Reporter.class.getSimpleName(); public static final String ACTION_FLUSH_TO_BUNDLE = AppGlobals.ACTION_NAMESPACE + ".FLUSH"; public static final String ACTION_NEW_BUNDLE = AppGlobals.ACTION_NAMESPACE + ".NEW_BUNDLE"; public static final String NEW_BUNDLE_ARG_BUNDLE = "bundle"; private boolean mIsStarted; /* The maximum number of Wi-Fi access points in a single observation. */ public static final int MAX_WIFIS_PER_LOCATION = 200; /* The maximum number of cells in a single observation */ public static final int MAX_CELLS_PER_LOCATION = 50; private Context mContext; private int mPhoneType; private StumblerBundle mBundle; private JSONObject mPreviousBundleJSON; public Reporter() { } public synchronized JSONObject getPreviousBundleJSON() { return mPreviousBundleJSON; } public synchronized void startup(Context context) { if (mIsStarted) { return; } mContext = context.getApplicationContext(); TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mPhoneType = tm.getPhoneType(); mIsStarted = true; mBundle = null; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiScanner.ACTION_WIFIS_SCANNED); intentFilter.addAction(CellScanner.ACTION_CELLS_SCANNED); intentFilter.addAction(GPSScanner.ACTION_GPS_UPDATED); intentFilter.addAction(ACTION_FLUSH_TO_BUNDLE); LocalBroadcastManager.getInstance(mContext).registerReceiver(this, intentFilter); } public synchronized void shutdown() { if (mContext == null) { return; } mIsStarted = false; Log.d(LOG_TAG, "shutdown"); flush(); LocalBroadcastManager.getInstance(mContext).unregisterReceiver(this); } private void receivedWifiMessage(Intent intent) { List<ScanResult> results = intent.getParcelableArrayListExtra(WifiScanner.ACTION_WIFIS_SCANNED_ARG_RESULTS); putWifiResults(results); } private void receivedCellMessage(Intent intent) { List<CellInfo> results = intent.getParcelableArrayListExtra(CellScanner.ACTION_CELLS_SCANNED_ARG_CELLS); putCellResults(results); } private void receivedGpsMessage(Intent intent) { String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT); if (subject.equals(GPSScanner.SUBJECT_NEW_LOCATION)) { Location newPosition = intent.getParcelableExtra(GPSScanner.NEW_LOCATION_ARG_LOCATION); // Only create StumblerBundle instances if the position exists if (newPosition != null) { flush(); mBundle = new StumblerBundle(newPosition, mPhoneType); } } } @Override public synchronized void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ACTION_FLUSH_TO_BUNDLE)) { flush(); return; } else if (action.equals(WifiScanner.ACTION_WIFIS_SCANNED)) { receivedWifiMessage(intent); } else if (action.equals(CellScanner.ACTION_CELLS_SCANNED)) { receivedCellMessage(intent); } else if (action.equals(GPSScanner.ACTION_GPS_UPDATED)) { // This is the common case receivedGpsMessage(intent); } if (mBundle != null && (mBundle.getWifiData().size() > MAX_WIFIS_PER_LOCATION || mBundle.getCellData().size() > MAX_CELLS_PER_LOCATION)) { // no gps for a while, have too much data, just bundle it flush(); } } public synchronized Map<String, ScanResult> getWifiData() { if (mBundle == null) { return null; } return mBundle.getWifiData(); } public synchronized Map<String, CellInfo> getCellData() { if (mBundle == null) { return null; } return mBundle.getCellData(); } public synchronized Location getGPSLocation() { if (mBundle == null) { return null; } return mBundle.getGpsPosition(); } private void putWifiResults(List<ScanResult> results) { if (mBundle == null) { return; } Map<String, ScanResult> currentWifiData = mBundle.getWifiData(); for (ScanResult result : results) { if (currentWifiData.size() > MAX_WIFIS_PER_LOCATION) { AppGlobals.guiLogInfo("Max wifi limit exceeded for this location, ignoring data."); return; } String key = result.BSSID; if (!currentWifiData.containsKey(key)) { currentWifiData.put(key, result); } } } private void putCellResults(List<CellInfo> cells) { if (mBundle == null) { return; } Map<String, CellInfo> currentCellData = mBundle.getCellData(); for (CellInfo result : cells) { if (currentCellData.size() > MAX_CELLS_PER_LOCATION) { AppGlobals.guiLogInfo("Max cell limit exceeded for this location, ignoring data."); return; } String key = result.getCellIdentity(); if (!currentCellData.containsKey(key)) { currentCellData.put(key, result); } } } public synchronized void flush() { JSONObject mlsObj; int wifiCount = 0; int cellCount = 0; if (mBundle == null) { return; } try { mlsObj = mBundle.toMLSJSON(); wifiCount = mlsObj.getInt(DataStorageContract.ReportsColumns.WIFI_COUNT); cellCount = mlsObj.getInt(DataStorageContract.ReportsColumns.CELL_COUNT); } catch (JSONException e) { Log.w(LOG_TAG, "Failed to convert bundle to JSON: " + e); mBundle = null; return; } if (AppGlobals.isDebug) { Log.d(LOG_TAG, "Received a MLS bundle" + mlsObj.toString()); } if (wifiCount + cellCount < 1) { mBundle = null; return; } mPreviousBundleJSON = mlsObj; AppGlobals.guiLogInfo("MLS record: " + mlsObj.toString()); Intent i = new Intent(ACTION_NEW_BUNDLE); i.putExtra(NEW_BUNDLE_ARG_BUNDLE, mBundle); i.putExtra(AppGlobals.ACTION_ARG_TIME, System.currentTimeMillis()); LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i); try { DataStorageManager.getInstance().insert(mlsObj.toString(), wifiCount, cellCount); } catch (IOException e) { Log.w(LOG_TAG, e.toString()); } mBundle = null; } }