summaryrefslogtreecommitdiffstats
path: root/mobile/android/stumbler/java/org/mozilla/mozstumbler
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/stumbler/java/org/mozilla/mozstumbler')
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java82
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java205
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java70
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SafeReceiver.java43
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java41
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java219
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java254
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java65
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java41
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java11
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java38
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java473
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/PersistedStats.java99
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java187
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java293
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java105
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java191
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java228
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java391
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java178
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerImplementation.java299
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java214
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java138
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java158
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java32
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java85
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/TelemetryWrapper.java35
-rw-r--r--mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java48
28 files changed, 0 insertions, 4223 deletions
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java
deleted file mode 100644
index 11a3bf4e0..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* 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;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-public class AppGlobals {
- public static final String LOG_PREFIX = "Stumbler_";
-
- /* All intent actions start with this string. Only locally broadcasted. */
- public static final String ACTION_NAMESPACE = "org.mozilla.mozstumbler.intent.action";
-
- /* Handle this for logging reporter info. */
- public static final String ACTION_GUI_LOG_MESSAGE = AppGlobals.ACTION_NAMESPACE + ".LOG_MESSAGE";
- public static final String ACTION_GUI_LOG_MESSAGE_EXTRA = ACTION_GUI_LOG_MESSAGE + ".MESSAGE";
-
- /* Defined here so that the Reporter class can access the time of an Intent in a generic fashion.
- * Classes should have their own constant that is assigned to this, for example,
- * WifiScanner has ACTION_WIFIS_SCANNED_ARG_TIME = ACTION_ARG_TIME.
- * This member definition in the broadcaster makes it clear what the extra Intent args are for that class. */
- public static final String ACTION_ARG_TIME = "time";
-
- /* Location constructor requires a named origin, these are created in the app. */
- public static final String LOCATION_ORIGIN_INTERNAL = "internal";
-
- public enum ActiveOrPassiveStumbling { ACTIVE_STUMBLING, PASSIVE_STUMBLING }
-
- /* In passive mode, only scan this many times for each gps. */
- public static final int PASSIVE_MODE_MAX_SCANS_PER_GPS = 3;
-
- /* These are set on startup. The appVersionName and code are not used in the service-only case. */
- public static String appVersionName = "0.0.0";
- public static int appVersionCode = 0;
- public static String appName = "StumblerService";
- public static boolean isDebug;
-
- /* The log activity will clear this periodically, and display the messages.
- * Always null when the stumbler service is used stand-alone. */
- public static volatile ConcurrentLinkedQueue<String> guiLogMessageBuffer;
-
- public static void guiLogError(String msg) {
- guiLogInfo(msg, "red", true);
- }
-
- public static void guiLogInfo(String msg) {
- guiLogInfo(msg, "white", false);
- }
-
- public static void guiLogInfo(String msg, String color, boolean isBold) {
- if (guiLogMessageBuffer != null) {
- if (isBold) {
- msg = "<b>" + msg + "</b>";
- }
- guiLogMessageBuffer.add("<font color='" + color +"'>" + msg + "</font>");
- }
- }
-
- public static String makeLogTag(String name) {
- final int maxLen = 23 - LOG_PREFIX.length();
- if (name.length() > maxLen) {
- name = name.substring(name.length() - maxLen, name.length());
- }
- return LOG_PREFIX + name;
- }
-
- public static final String ACTION_TEST_SETTING_ENABLED = "stumbler-test-setting-enabled";
- public static final String ACTION_TEST_SETTING_DISABLED = "stumbler-test-setting-disabled";
-
- // Histogram values
- public static final String TELEMETRY_TIME_BETWEEN_UPLOADS_SEC = "STUMBLER_TIME_BETWEEN_UPLOADS_SEC";
- public static final String TELEMETRY_BYTES_UPLOADED_PER_SEC = "STUMBLER_VOLUME_BYTES_UPLOADED_PER_SEC";
- public static final String TELEMETRY_TIME_BETWEEN_STARTS_SEC = "STUMBLER_TIME_BETWEEN_START_SEC";
- public static final String TELEMETRY_BYTES_PER_UPLOAD = "STUMBLER_UPLOAD_BYTES";
- public static final String TELEMETRY_OBSERVATIONS_PER_UPLOAD = "STUMBLER_UPLOAD_OBSERVATION_COUNT";
- public static final String TELEMETRY_CELLS_PER_UPLOAD = "STUMBLER_UPLOAD_CELL_COUNT";
- public static final String TELEMETRY_WIFIS_PER_UPLOAD = "STUMBLER_UPLOAD_WIFI_AP_COUNT";
- public static final String TELEMETRY_OBSERVATIONS_PER_DAY = "STUMBLER_OBSERVATIONS_PER_DAY";
- public static final String TELEMETRY_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC = "STUMBLER_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC";
-}
-
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java
deleted file mode 100644
index fa00f29e9..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/* 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;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.location.Location;
-import android.os.Build.VERSION;
-import android.text.TextUtils;
-import android.util.Log;
-
-public final class Prefs {
- private static final String LOG_TAG = AppGlobals.makeLogTag(Prefs.class.getSimpleName());
- private static final String NICKNAME_PREF = "nickname";
- private static final String USER_AGENT_PREF = "user-agent";
- private static final String VALUES_VERSION_PREF = "values_version";
- private static final String WIFI_ONLY = "wifi_only";
- private static final String LAT_PREF = "lat_pref";
- private static final String LON_PREF = "lon_pref";
- private static final String GEOFENCE_HERE = "geofence_here";
- private static final String GEOFENCE_SWITCH = "geofence_switch";
- private static final String FIREFOX_SCAN_ENABLED = "firefox_scan_on";
- private static final String MOZ_API_KEY = "moz_api_key";
- private static final String WIFI_SCAN_ALWAYS = "wifi_scan_always";
- private static final String LAST_ATTEMPTED_UPLOAD_TIME = "last_attempted_upload_time";
- // Public for MozStumbler to use for manual upgrade of old prefs.
- public static final String PREFS_FILE = Prefs.class.getSimpleName();
-
- private final SharedPreferences mSharedPrefs;
- static private Prefs sInstance;
-
- private Prefs(Context context) {
- mSharedPrefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE);
- if (getPrefs().getInt(VALUES_VERSION_PREF, -1) != AppGlobals.appVersionCode) {
- Log.i(LOG_TAG, "Version of the application has changed. Updating default values.");
- // Remove old keys
- getPrefs().edit()
- .remove("reports")
- .remove("power_saving_mode")
- .commit();
-
- getPrefs().edit().putInt(VALUES_VERSION_PREF, AppGlobals.appVersionCode).commit();
- getPrefs().edit().commit();
- }
- }
-
- public static Prefs getInstance(Context c) {
- if (sInstance == null) {
- sInstance = new Prefs(c);
- }
- return sInstance;
- }
-
- // Allows code without a context handle to grab the prefs. The caller must null check the return value.
- public static Prefs getInstanceWithoutContext() {
- return sInstance;
- }
-
- ///
- /// Setters
- ///
- public synchronized void setUserAgent(String userAgent) {
- setStringPref(USER_AGENT_PREF, userAgent);
- }
-
- public synchronized void setUseWifiOnly(boolean state) {
- setBoolPref(WIFI_ONLY, state);
- }
-
- public synchronized void setGeofenceEnabled(boolean state) {
- setBoolPref(GEOFENCE_SWITCH, state);
- }
-
- public synchronized void setGeofenceHere(boolean flag) {
- setBoolPref(GEOFENCE_HERE, flag);
- }
-
- public synchronized void setGeofenceLocation(Location location) {
- SharedPreferences.Editor editor = getPrefs().edit();
- editor.putFloat(LAT_PREF, (float) location.getLatitude());
- editor.putFloat(LON_PREF, (float) location.getLongitude());
- apply(editor);
- }
-
- public synchronized void setMozApiKey(String s) {
- setStringPref(MOZ_API_KEY, s);
- }
-
- ///
- /// Getters
- ///
- public synchronized String getUserAgent() {
- String s = getStringPref(USER_AGENT_PREF);
- return (s == null)? AppGlobals.appName + "/" + AppGlobals.appVersionName : s;
- }
-
- public synchronized boolean getFirefoxScanEnabled() {
- return getBoolPrefWithDefault(FIREFOX_SCAN_ENABLED, false);
- }
-
- public synchronized String getMozApiKey() {
- String s = getStringPref(MOZ_API_KEY);
- return (s == null)? "no-mozilla-api-key" : s;
- }
-
- public synchronized boolean getGeofenceEnabled() {
- return getBoolPrefWithDefault(GEOFENCE_SWITCH, false);
- }
-
- public synchronized boolean getGeofenceHere() {
- return getBoolPrefWithDefault(GEOFENCE_HERE, false);
- }
-
- public synchronized Location getGeofenceLocation() {
- Location loc = new Location(AppGlobals.LOCATION_ORIGIN_INTERNAL);
- loc.setLatitude(getPrefs().getFloat(LAT_PREF, 0));
- loc.setLongitude(getPrefs().getFloat(LON_PREF,0));
- return loc;
- }
-
- // This is the time an upload was last attempted, not necessarily successful.
- // Used to ensure upload attempts aren't happening too frequently.
- public synchronized long getLastAttemptedUploadTime() {
- return getPrefs().getLong(LAST_ATTEMPTED_UPLOAD_TIME, 0);
- }
-
- public synchronized String getNickname() {
- String nickname = getStringPref(NICKNAME_PREF);
- if (nickname != null) {
- nickname = nickname.trim();
- }
- return TextUtils.isEmpty(nickname) ? null : nickname;
- }
-
- public synchronized void setFirefoxScanEnabled(boolean on) {
- setBoolPref(FIREFOX_SCAN_ENABLED, on);
- }
-
- public synchronized void setLastAttemptedUploadTime(long time) {
- SharedPreferences.Editor editor = getPrefs().edit();
- editor.putLong(LAST_ATTEMPTED_UPLOAD_TIME, time);
- apply(editor);
- }
-
- public synchronized void setNickname(String nick) {
- if (nick != null) {
- nick = nick.trim();
- if (nick.length() > 0) {
- setStringPref(NICKNAME_PREF, nick);
- }
- }
- }
-
- public synchronized boolean getUseWifiOnly() {
- return getBoolPrefWithDefault(WIFI_ONLY, true);
- }
-
- public synchronized boolean getWifiScanAlways() {
- return getBoolPrefWithDefault(WIFI_SCAN_ALWAYS, false);
- }
-
- public synchronized void setWifiScanAlways(boolean b) {
- setBoolPref(WIFI_SCAN_ALWAYS, b);
- }
-
- ///
- /// Privates
- ///
-
- private String getStringPref(String key) {
- return getPrefs().getString(key, null);
- }
-
- private boolean getBoolPrefWithDefault(String key, boolean def) {
- return getPrefs().getBoolean(key, def);
- }
-
- private void setBoolPref(String key, Boolean state) {
- SharedPreferences.Editor editor = getPrefs().edit();
- editor.putBoolean(key,state);
- apply(editor);
- }
-
- private void setStringPref(String key, String value) {
- SharedPreferences.Editor editor = getPrefs().edit();
- editor.putString(key, value);
- apply(editor);
- }
-
- @TargetApi(9)
- private static void apply(SharedPreferences.Editor editor) {
- if (VERSION.SDK_INT >= 9) {
- editor.apply();
- } else if (!editor.commit()) {
- Log.e(LOG_TAG, "", new IllegalStateException("commit() failed?!"));
- }
- }
-
- private SharedPreferences getPrefs() {
- return mSharedPrefs;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java
deleted file mode 100644
index 388abba15..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* 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.mainthread;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.stumblerthread.StumblerService;
-
-/**
- * Starts the StumblerService, an Intent service, which by definition runs on its own thread.
- * Registered as a local broadcast receiver in SafeReceiver.
- * Starts the StumblerService in passive listening mode.
- *
- * The received intent contains enabled state, upload API key and user agent,
- * and is used to initialize the StumblerService.
- */
-public class LocalPreferenceReceiver extends BroadcastReceiver {
- // This allows global debugging logs to be enabled by doing
- // |adb shell setprop log.tag.PassiveStumbler DEBUG|
- static final String LOG_TAG = "PassiveStumbler";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
-
- // This value is cached, so if |setprop| is performed (as described on the LOG_TAG above),
- // then the start/stop intent must be resent by toggling the setting or stopping/starting Fennec.
- // This does not guard against dumping PII (PII in stumbler is location, wifi BSSID, cell tower details).
- AppGlobals.isDebug = Log.isLoggable(LOG_TAG, Log.DEBUG);
-
- StumblerService.sFirefoxStumblingEnabled.set(intent.getBooleanExtra("enabled", false));
-
- if (!StumblerService.sFirefoxStumblingEnabled.get()) {
- Log.d(LOG_TAG, "Stopping StumblerService | isDebug:" + AppGlobals.isDebug);
- // This calls the service's onDestroy(), and the service's onHandleIntent(...) is not called
- context.stopService(new Intent(context, StumblerService.class));
- // For testing service messages were received
- context.sendBroadcast(new Intent(AppGlobals.ACTION_TEST_SETTING_DISABLED));
- return;
- }
-
- // For testing service messages were received
- context.sendBroadcast(new Intent(AppGlobals.ACTION_TEST_SETTING_ENABLED));
-
- Log.d(LOG_TAG, "Sending passive start message | isDebug:" + AppGlobals.isDebug);
-
- final Intent startServiceIntent = new Intent(context, StumblerService.class);
-
- startServiceIntent.putExtra(StumblerService.ACTION_START_PASSIVE, true);
- startServiceIntent.putExtra(
- StumblerService.ACTION_EXTRA_MOZ_API_KEY,
- intent.getStringExtra("moz_mozilla_api_key")
- );
- startServiceIntent.putExtra(
- StumblerService.ACTION_EXTRA_USER_AGENT,
- intent.getStringExtra("user_agent")
- );
-
- context.startService(startServiceIntent);
- }
-}
-
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SafeReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SafeReceiver.java
deleted file mode 100644
index e145dbb0f..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SafeReceiver.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 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.mainthread;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-
-/**
- * Responsible for registering LocalPreferenceReceiver as a receiver with LocalBroadcastManager.
- * This receiver is registered in the AndroidManifest.xml
- */
-public class SafeReceiver extends BroadcastReceiver {
- static final String LOG_TAG = "StumblerSafeReceiver";
- static final String PREFERENCE_INTENT_FILTER = "STUMBLER_PREF";
-
- private boolean registeredLocalReceiver = false;
-
- @Override
- public synchronized void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
-
- if (registeredLocalReceiver) {
- return;
- }
-
- LocalBroadcastManager.getInstance(context).registerReceiver(
- new LocalPreferenceReceiver(),
- new IntentFilter(PREFERENCE_INTENT_FILTER)
- );
-
- Log.d(LOG_TAG, "Registered local preference listener");
-
- registeredLocalReceiver = true;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
deleted file mode 100644
index eaaab3423..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 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.mainthread;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.stumblerthread.StumblerService;
-
-/**
- * Responsible for starting StumblerService in response to
- * BOOT_COMPLETE and EXTERNAL_APPLICATIONS_AVAILABLE system intents.
- */
-public class SystemReceiver extends BroadcastReceiver {
- static final String LOG_TAG = "StumblerSystemReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
-
- final String action = intent.getAction();
-
- if (!TextUtils.equals(action, Intent.ACTION_BOOT_COMPLETED) && !TextUtils.equals(action, Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)) {
- // This is not the broadcast you are looking for.
- return;
- }
-
- final Intent startServiceIntent = new Intent(context, StumblerService.class);
- startServiceIntent.putExtra(StumblerService.ACTION_NOT_FROM_HOST_APP, true);
- context.startService(startServiceIntent);
-
- Log.d(LOG_TAG, "Responded to a system intent");
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java
deleted file mode 100644
index 8f7f19c8d..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/* 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 android.util.Log;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.mozstumbler.service.AppGlobals;
-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.cellscanner.CellInfo;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.GPSScanner;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.WifiScanner;
-
-public final class Reporter extends BroadcastReceiver {
- private static final String LOG_TAG = AppGlobals.makeLogTag(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";
- private boolean mIsStarted;
-
- /* The maximum number of Wi-Fi access points in a single observation. */
- private static final int MAX_WIFIS_PER_LOCATION = 200;
-
- /* The maximum number of cells in a single observation */
- private static final int MAX_CELLS_PER_LOCATION = 50;
-
- private Context mContext;
- private int mPhoneType;
-
- private StumblerBundle mBundle;
-
- Reporter() {}
-
- private void resetData() {
- mBundle = null;
- }
-
- public void flush() {
- reportCollectedLocation();
- }
-
- void startup(Context context) {
- if (mIsStarted) {
- return;
- }
-
- mContext = context.getApplicationContext();
- TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm != null) {
- mPhoneType = tm.getPhoneType();
- } else {
- Log.d(LOG_TAG, "No telephony manager.");
- mPhoneType = TelephonyManager.PHONE_TYPE_NONE;
- }
-
- mIsStarted = true;
-
- resetData();
- 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);
- }
-
- 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 (GPSScanner.SUBJECT_NEW_LOCATION.equals(subject)) {
- reportCollectedLocation();
- Location newPosition = intent.getParcelableExtra(GPSScanner.NEW_LOCATION_ARG_LOCATION);
- mBundle = (newPosition != null) ? new StumblerBundle(newPosition, mPhoneType) : mBundle;
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- switch (action) {
- case ACTION_FLUSH_TO_BUNDLE:
- flush();
- return;
- case WifiScanner.ACTION_WIFIS_SCANNED:
- receivedWifiMessage(intent);
- break;
- case CellScanner.ACTION_CELLS_SCANNED:
- receivedCellMessage(intent);
- break;
- case GPSScanner.ACTION_GPS_UPDATED:
- // Calls reportCollectedLocation, this is the ideal case
- receivedGpsMessage(intent);
- break;
- }
-
- 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
- reportCollectedLocation();
- }
- }
-
- 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) {
- 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) {
- return;
- }
- String key = result.getCellIdentity();
- if (!currentCellData.containsKey(key)) {
- currentCellData.put(key, result);
- }
- }
- }
-
- private void reportCollectedLocation() {
- if (mBundle == null) {
- return;
- }
-
- storeBundleAsJSON(mBundle);
-
- mBundle.wasSent();
- }
-
- private void storeBundleAsJSON(StumblerBundle bundle) {
- JSONObject mlsObj;
- int wifiCount = 0;
- int cellCount = 0;
- try {
- mlsObj = bundle.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);
- return;
- }
-
- if (AppGlobals.isDebug) {
- // PII: do not log the bundle without obfuscating it
- Log.d(LOG_TAG, "Received bundle");
- }
-
- if (wifiCount + cellCount < 1) {
- return;
- }
-
- try {
- DataStorageManager.getInstance().insert(mlsObj.toString(), wifiCount, cellCount);
- } catch (IOException e) {
- Log.w(LOG_TAG, e.toString());
- }
- }
-}
-
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
deleted file mode 100644
index 5d1a278b9..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/* 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.Manifest;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.location.Location;
-import android.os.AsyncTask;
-import android.support.v4.content.ContextCompat;
-import android.util.Log;
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.Prefs;
-import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
-import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager;
-import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver;
-import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
-
-// In stand-alone service mode (a.k.a passive scanning mode), this is created from PassiveServiceReceiver (by calling startService).
-// The StumblerService is a sticky unbound service in this usage.
-//
-public class StumblerService extends PersistentIntentService
- implements DataStorageManager.StorageIsEmptyTracker {
- private static final String LOG_TAG = AppGlobals.makeLogTag(StumblerService.class.getSimpleName());
- public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE;
- public static final String ACTION_START_PASSIVE = ACTION_BASE + ".START_PASSIVE";
- public static final String ACTION_EXTRA_MOZ_API_KEY = ACTION_BASE + ".MOZKEY";
- public static final String ACTION_EXTRA_USER_AGENT = ACTION_BASE + ".USER_AGENT";
- public static final String ACTION_NOT_FROM_HOST_APP = ACTION_BASE + ".NOT_FROM_HOST";
- public static final AtomicBoolean sFirefoxStumblingEnabled = new AtomicBoolean();
- protected final ScanManager mScanManager = new ScanManager();
- protected final Reporter mReporter = new Reporter();
-
- // This is a delay before the single-shot upload is attempted. The number is arbitrary
- // and used to avoid startup tasks bunching up.
- private static final int DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE = 2;
-
- // This is the frequency of the repeating upload alarm in active scanning mode.
- private static final int FREQUENCY_IN_SEC_OF_UPLOAD_IN_ACTIVE_MODE = 5 * 60;
-
- // Used to guard against attempting to upload too frequently in passive mode.
- private static final long PASSIVE_UPLOAD_FREQ_GUARD_MSEC = 5 * 60 * 1000;
-
- public StumblerService() {
- this("StumblerService");
- }
-
- public StumblerService(String name) {
- super(name);
- }
-
- public boolean isScanning() {
- return mScanManager.isScanning();
- }
-
- public void startScanning() {
- mScanManager.startScanning(this);
- }
-
- // This is optional, not used in Fennec, and is for clients to specify a (potentially long) list
- // of blocklisted SSIDs/BSSIDs
- public void setWifiBlockList(WifiBlockListInterface list) {
- mScanManager.setWifiBlockList(list);
- }
-
- public Prefs getPrefs(Context c) {
- return Prefs.getInstance(c);
- }
-
- public void checkPrefs() {
- mScanManager.checkPrefs();
- }
-
- public int getLocationCount() {
- return mScanManager.getLocationCount();
- }
-
- public double getLatitude() {
- return mScanManager.getLatitude();
- }
-
- public double getLongitude() {
- return mScanManager.getLongitude();
- }
-
- public Location getLocation() {
- return mScanManager.getLocation();
- }
-
- public int getWifiStatus() {
- return mScanManager.getWifiStatus();
- }
-
- public int getAPCount() {
- return mScanManager.getAPCount();
- }
-
- public int getVisibleAPCount() {
- return mScanManager.getVisibleAPCount();
- }
-
- public int getCellInfoCount() {
- return mScanManager.getCellInfoCount();
- }
-
- public boolean isGeofenced () {
- return mScanManager.isGeofenced();
- }
-
- // Previously this was done in onCreate(). Moved out of that so that in the passive standalone service
- // use (i.e. Fennec), init() can be called from this class's dedicated thread.
- // Safe to call more than once, ensure added code complies with that intent.
- protected void init() {
- // Ensure Prefs is created, so internal utility code can use getInstanceWithoutContext
- Prefs.getInstance(this);
- DataStorageManager.createGlobalInstance(this, this);
-
- mReporter.startup(this);
- }
-
- // Called from the main thread.
- @Override
- public void onCreate() {
- super.onCreate();
- setIntentRedelivery(true);
- }
-
- // Called from the main thread
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (!mScanManager.isScanning()) {
- return;
- }
-
- // Used to move these disk I/O ops off the calling thread. The current operations here are synchronized,
- // however instead of creating another thread (if onDestroy grew to have concurrency complications)
- // we could be messaging the stumbler thread to perform a shutdown function.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "onDestroy");
- }
-
- if (!sFirefoxStumblingEnabled.get()) {
- Prefs.getInstance(StumblerService.this).setFirefoxScanEnabled(false);
- }
-
- if (DataStorageManager.getInstance() != null) {
- try {
- DataStorageManager.getInstance().saveCurrentReportsToDisk();
- } catch (IOException ex) {
- AppGlobals.guiLogInfo(ex.toString());
- Log.e(LOG_TAG, "Exception in onDestroy saving reports" + ex.toString());
- }
- }
- return null;
- }
- }.execute();
-
- mReporter.shutdown();
- mScanManager.stopScanning();
- }
-
- // This is the entry point for the stumbler thread.
- @Override
- protected void onHandleIntent(Intent intent) {
- // Do init() in all cases, there is no cost, whereas it is easy to add code that depends on this.
- init();
-
- // Post-init(), set the mode to passive.
- mScanManager.setPassiveMode(true);
-
- if (!hasLocationPermission()) {
- Log.d(LOG_TAG, "Location permission not granted. Aborting.");
- return;
- }
-
- if (intent == null) {
- return;
- }
-
- final boolean isScanEnabledInPrefs = Prefs.getInstance(this).getFirefoxScanEnabled();
-
- if (!isScanEnabledInPrefs && intent.getBooleanExtra(ACTION_NOT_FROM_HOST_APP, false)) {
- stopSelf();
- return;
- }
-
- boolean hasFilesWaiting = !DataStorageManager.getInstance().isDirEmpty();
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "Files waiting:" + hasFilesWaiting);
- }
- if (hasFilesWaiting) {
- // non-empty on startup, schedule an upload
- // This is the only upload trigger in Firefox mode
- // Firefox triggers this ~4 seconds after startup (after Gecko is loaded), add a small delay to avoid
- // clustering with other operations that are triggered at this time.
- final long lastAttemptedTime = Prefs.getInstance(this).getLastAttemptedUploadTime();
- final long timeNow = System.currentTimeMillis();
-
- if (timeNow - lastAttemptedTime < PASSIVE_UPLOAD_FREQ_GUARD_MSEC) {
- // TODO Consider telemetry to track this.
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "Upload attempt too frequent.");
- }
- } else {
- Prefs.getInstance(this).setLastAttemptedUploadTime(timeNow);
- UploadAlarmReceiver.scheduleAlarm(this, DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE, false /* no repeat*/);
- }
- }
-
- if (!isScanEnabledInPrefs) {
- Prefs.getInstance(this).setFirefoxScanEnabled(true);
- }
-
- String apiKey = intent.getStringExtra(ACTION_EXTRA_MOZ_API_KEY);
- if (apiKey != null && !apiKey.equals(Prefs.getInstance(this).getMozApiKey())) {
- Prefs.getInstance(this).setMozApiKey(apiKey);
- }
-
- String userAgent = intent.getStringExtra(ACTION_EXTRA_USER_AGENT);
- if (userAgent != null && !userAgent.equals(Prefs.getInstance(this).getUserAgent())) {
- Prefs.getInstance(this).setUserAgent(userAgent);
- }
-
- if (!mScanManager.isScanning()) {
- startScanning();
- }
- }
-
- // Note that in passive mode, having data isn't an upload trigger, it is triggered by the start intent
- @Override
- public void notifyStorageStateEmpty(boolean isEmpty) {
- if (isEmpty) {
- UploadAlarmReceiver.cancelAlarm(this, !mScanManager.isPassiveMode());
- } else if (!mScanManager.isPassiveMode()) {
- UploadAlarmReceiver.scheduleAlarm(this, FREQUENCY_IN_SEC_OF_UPLOAD_IN_ACTIVE_MODE, true /* repeating */);
- }
- }
-
- private boolean hasLocationPermission() {
- return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java
deleted file mode 100644
index 6354cb0cc..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/* 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.blocklist;
-
-import android.net.wifi.ScanResult;
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-public final class BSSIDBlockList {
- private static final String LOG_TAG = AppGlobals.makeLogTag(BSSIDBlockList.class.getSimpleName());
- private static final String NULL_BSSID = "000000000000";
- private static final String WILDCARD_BSSID = "ffffffffffff";
- private static final Pattern BSSID_PATTERN = Pattern.compile("([0-9a-f]{12})");
- private static String[] sOuiList = new String[]{};
-
- private BSSIDBlockList() {
- }
-
- public static void setFilterList(String[] list) {
- sOuiList = list;
- }
-
- public static boolean contains(ScanResult scanResult) {
- String BSSID = scanResult.BSSID;
- if (BSSID == null || NULL_BSSID.equals(BSSID) || WILDCARD_BSSID.equals(BSSID)) {
- return true; // blocked!
- }
-
- if (!isCanonicalBSSID(BSSID)) {
- Log.w(LOG_TAG, "", new IllegalArgumentException("Unexpected BSSID format: " + BSSID));
- return true; // blocked!
- }
-
- for (String oui : sOuiList) {
- if (BSSID.startsWith(oui)) {
- return true; // blocked!
- }
- }
-
- return false; // OK
- }
-
- public static String canonicalizeBSSID(String BSSID) {
- if (BSSID == null) {
- return "";
- }
-
- if (isCanonicalBSSID(BSSID)) {
- return BSSID;
- }
-
- // Some devices may return BSSIDs with ':', '-' or '.' delimiters.
- BSSID = BSSID.toLowerCase(Locale.US).replaceAll("[\\-\\.:]", "");
-
- return isCanonicalBSSID(BSSID) ? BSSID : "";
- }
-
- private static boolean isCanonicalBSSID(String BSSID) {
- return BSSID_PATTERN.matcher(BSSID).matches();
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java
deleted file mode 100644
index f5086ab34..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 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.blocklist;
-
-import android.net.wifi.ScanResult;
-
-public final class SSIDBlockList {
- private static String[] sPrefixList = new String[]{};
- private static String[] sSuffixList = new String[]{"_nomap"};
-
- private SSIDBlockList() {
- }
-
- public static void setFilterLists(String[] prefix, String[] suffix) {
- sPrefixList = prefix;
- sSuffixList = suffix;
- }
-
- public static boolean contains(ScanResult scanResult) {
- String SSID = scanResult.SSID;
- if (SSID == null) {
- return true; // no SSID?
- }
-
- for (String prefix : sPrefixList) {
- if (SSID.startsWith(prefix)) {
- return true; // blocked!
- }
- }
-
- for (String suffix : sSuffixList) {
- if (SSID.endsWith(suffix)) {
- return true; // blocked!
- }
- }
-
- return false; // OK
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java
deleted file mode 100644
index 0e940cdc9..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* 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.blocklist;
-
-public interface WifiBlockListInterface {
- String[] getSsidPrefixList();
- String[] getSsidSuffixList();
- String[] getBssidOuiList();
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java
deleted file mode 100644
index 2aaeb05ff..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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.datahandling;
-
-public final class DataStorageContract {
-
- public static class ReportsColumns {
- public static final String LAT = "lat";
- public static final String LON = "lon";
- public static final String TIME = "timestamp";
- public static final String ACCURACY = "accuracy";
- public static final String ALTITUDE = "altitude";
- public static final String RADIO = "radio";
- public static final String CELL = "cell";
- public static final String WIFI = "wifi";
- public static final String CELL_COUNT = "cell_count";
- public static final String WIFI_COUNT = "wifi_count";
- public static final String HEADING = "heading";
- public static final String SPEED = "speed";
- public static final String PRESSURE = "pressure";
- }
-
- public static class Stats {
- public static final String KEY_VERSION = "version_code";
- public static final int VERSION_CODE = 2;
- public static final String KEY_BYTES_SENT = "bytes_sent";
- public static final String KEY_LAST_UPLOAD_TIME = "last_upload_time";
- public static final String KEY_OBSERVATIONS_SENT = "observations_sent";
- public static final String KEY_WIFIS_SENT = "wifis_sent";
- public static final String KEY_CELLS_SENT = "cells_sent";
- public static final String KEY_OBSERVATIONS_PER_DAY = "obs_per_day";
- }
-
- private DataStorageContract() {
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
deleted file mode 100644
index adaaea4dc..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/* 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.datahandling;
-
-import android.content.Context;
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.utils.Zipper;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-import java.util.Properties;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/* Stores reports in memory (mCurrentReports) until MAX_REPORTS_IN_MEMORY,
- * then writes them to disk as a .gz file. The name of the file has
- * the time written, the # of reports, and the # of cells and wifis.
- *
- * Each .gz file is typically 1-5KB. File name example: reports-t1406863343313-r4-w25-c7.gz
- *
- * The sync stats are written as a key-value pair file (not zipped).
- *
- * The tricky bit is the mCurrentReportsSendBuffer. When the uploader code begins accessing the
- * report batches, mCurrentReports gets pushed to mCurrentReportsSendBuffer.
- * The mCurrentReports is then cleared, and can continue receiving new reports.
- * From the uploader perspective, mCurrentReportsSendBuffer looks and acts exactly like a batch file on disk.
- *
- * If the network is reasonably active, and reporting is slow enough, there is no disk I/O, it all happens
- * in-memory.
- *
- * Also of note: the in-memory buffers (both mCurrentReports and mCurrentReportsSendBuffer) are saved
- * when the service is destroyed.
- */
-public class DataStorageManager {
- private static final String LOG_TAG = AppGlobals.makeLogTag(DataStorageManager.class.getSimpleName());
-
- // The max number of reports stored in the mCurrentReports. Each report is a GPS location plus wifi and cell scan.
- // After this size is reached, data is persisted to disk, mCurrentReports is cleared.
- private static final int MAX_REPORTS_IN_MEMORY = 50;
-
- // Used to cap the amount of data stored. When this limit is hit, no more data is saved to disk
- // until the data is uploaded, or and data exceeds DEFAULT_MAX_WEEKS_DATA_ON_DISK.
- private static final long DEFAULT_MAX_BYTES_STORED_ON_DISK = 1024 * 250; // 250 KiB max by default
-
- // Used as a safeguard to ensure stumbling data is not persisted. The intended use case of the stumbler lib is not
- // for long-term storage, and so if ANY data on disk is this old, ALL data is wiped as a privacy mechanism.
- private static final int DEFAULT_MAX_WEEKS_DATA_ON_DISK = 2;
-
- // Set to the default value specified above.
- private final long mMaxBytesDiskStorage;
-
- // Set to the default value specified above.
- private final int mMaxWeeksStored;
-
- private final ReportBatchBuilder mCurrentReports = new ReportBatchBuilder();
- private final File mReportsDir;
- private final File mStatsFile;
- private final StorageIsEmptyTracker mTracker;
-
- private static DataStorageManager sInstance;
-
- private ReportBatch mCurrentReportsSendBuffer;
- private ReportBatchIterator mReportBatchIterator;
- private final ReportFileList mFileList;
- private Timer mFlushMemoryBuffersToDiskTimer;
- private final PersistedStats mPersistedOnDiskUploadStats;
-
- static final String SEP_REPORT_COUNT = "-r";
- static final String SEP_WIFI_COUNT = "-w";
- static final String SEP_CELL_COUNT = "-c";
- static final String SEP_TIME_MS = "-t";
- static final String FILENAME_PREFIX = "reports";
- static final String MEMORY_BUFFER_NAME = "in memory send buffer";
-
- public static class QueuedCounts {
- public final int mReportCount;
- public final int mWifiCount;
- public final int mCellCount;
- public final long mBytes;
-
- QueuedCounts(int reportCount, int wifiCount, int cellCount, long bytes) {
- this.mReportCount = reportCount;
- this.mWifiCount = wifiCount;
- this.mCellCount = cellCount;
- this.mBytes = bytes;
- }
- }
-
- /* Some data is calculated on-demand, don't abuse this function */
- public QueuedCounts getQueuedCounts() {
- int reportCount = mFileList.mReportCount + mCurrentReports.reports.size();
- int wifiCount = mFileList.mWifiCount + mCurrentReports.wifiCount;
- int cellCount = mFileList.mCellCount + mCurrentReports.cellCount;
- long bytes = 0;
-
- if (mCurrentReports.reports.size() > 0) {
- try {
- bytes = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes()).length;
- } catch (IOException ex) {
- Log.e(LOG_TAG, "Zip error in getQueuedCounts()", ex);
- }
-
- if (mFileList.mReportCount > 0) {
- bytes += mFileList.mFilesOnDiskBytes;
- }
- }
-
- if (mCurrentReportsSendBuffer != null) {
- reportCount += mCurrentReportsSendBuffer.reportCount;
- wifiCount += mCurrentReportsSendBuffer.wifiCount;
- cellCount += mCurrentReportsSendBuffer.cellCount;
- bytes += mCurrentReportsSendBuffer.data.length;
- }
- return new QueuedCounts(reportCount, wifiCount, cellCount, bytes);
- }
-
- private static class ReportFileList {
- File[] mFiles;
- int mReportCount;
- int mWifiCount;
- int mCellCount;
- long mFilesOnDiskBytes;
-
- public ReportFileList() {}
- public ReportFileList(ReportFileList other) {
- if (other == null) {
- return;
- }
-
- if (other.mFiles != null) {
- mFiles = other.mFiles.clone();
- }
-
- mReportCount = other.mReportCount;
- mWifiCount = other.mWifiCount;
- mCellCount = other.mCellCount;
- mFilesOnDiskBytes = other.mFilesOnDiskBytes;
- }
-
- void update(File directory) {
- mFiles = directory.listFiles();
- if (mFiles == null) {
- return;
- }
-
- if (AppGlobals.isDebug) {
- for (File f : mFiles) {
- Log.d("StumblerFiles", f.getName());
- }
- }
-
- mFilesOnDiskBytes = mReportCount = mWifiCount = mCellCount = 0;
- for (File f : mFiles) {
- mReportCount += (int) getLongFromFilename(f.getName(), SEP_REPORT_COUNT);
- mWifiCount += (int) getLongFromFilename(f.getName(), SEP_WIFI_COUNT);
- mCellCount += (int) getLongFromFilename(f.getName(), SEP_CELL_COUNT);
- mFilesOnDiskBytes += f.length();
- }
- }
- }
-
- public static class ReportBatch {
- public final String filename;
- public final byte[] data;
- public final int reportCount;
- public final int wifiCount;
- public final int cellCount;
-
- public ReportBatch(String filename, byte[] data, int reportCount, int wifiCount, int cellCount) {
- this.filename = filename;
- this.data = data;
- this.reportCount = reportCount;
- this.wifiCount = wifiCount;
- this.cellCount = cellCount;
- }
- }
-
- private static class ReportBatchBuilder {
- public final ArrayList<String> reports = new ArrayList<String>();
- public int wifiCount;
- public int cellCount;
- }
-
- private static class ReportBatchIterator {
- public ReportBatchIterator(ReportFileList list) {
- fileList = new ReportFileList(list);
- }
-
- static final int BATCH_INDEX_FOR_MEM_BUFFER = -1;
- public int currentIndex = BATCH_INDEX_FOR_MEM_BUFFER;
- public final ReportFileList fileList;
- }
-
- public interface StorageIsEmptyTracker {
- public void notifyStorageStateEmpty(boolean isEmpty);
- }
-
- private String getStorageDir(Context c) {
- File dir = c.getFilesDir();
- if (!dir.exists()) {
- boolean ok = dir.mkdirs();
- if (!ok) {
- Log.d(LOG_TAG, "getStorageDir: error in mkdirs()");
- }
- }
-
- return dir.getPath();
- }
-
- public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker) {
- DataStorageManager.createGlobalInstance(context, tracker,
- DEFAULT_MAX_BYTES_STORED_ON_DISK, DEFAULT_MAX_WEEKS_DATA_ON_DISK);
- }
-
- public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker,
- long maxBytesStoredOnDisk, int maxWeeksDataStored) {
- if (sInstance != null) {
- return;
- }
- sInstance = new DataStorageManager(context, tracker, maxBytesStoredOnDisk, maxWeeksDataStored);
- }
-
- public static synchronized DataStorageManager getInstance() {
- return sInstance;
- }
-
- private DataStorageManager(Context c, StorageIsEmptyTracker tracker,
- long maxBytesStoredOnDisk, int maxWeeksDataStored) {
- mMaxBytesDiskStorage = maxBytesStoredOnDisk;
- mMaxWeeksStored = maxWeeksDataStored;
- mTracker = tracker;
- final String baseDir = getStorageDir(c);
- mStatsFile = new File(baseDir, "upload_stats.ini");
- mReportsDir = new File(baseDir + "/reports");
- if (!mReportsDir.exists()) {
- mReportsDir.mkdirs();
- }
- mFileList = new ReportFileList();
- mFileList.update(mReportsDir);
- mPersistedOnDiskUploadStats = new PersistedStats(baseDir);
- }
-
- public synchronized int getMaxWeeksStored() {
- return mMaxWeeksStored;
- }
-
- private static byte[] readFile(File file) throws IOException {
- final RandomAccessFile f = new RandomAccessFile(file, "r");
- try {
- final byte[] data = new byte[(int) f.length()];
- f.readFully(data);
- return data;
- } finally {
- f.close();
- }
- }
-
- public synchronized boolean isDirEmpty() {
- return (mFileList.mFiles == null || mFileList.mFiles.length < 1);
- }
-
- /* Pass filename returned from dataToSend() */
- public synchronized boolean delete(String filename) {
- if (filename.equals(MEMORY_BUFFER_NAME)) {
- mCurrentReportsSendBuffer = null;
- return true;
- }
-
- final File file = new File(mReportsDir, filename);
- final boolean ok = file.delete();
- mFileList.update(mReportsDir);
- return ok;
- }
-
- private static long getLongFromFilename(String name, String separator) {
- final int s = name.indexOf(separator) + separator.length();
- int e = name.indexOf('-', s);
- if (e < 0) {
- e = name.indexOf('.', s);
- }
- return Long.parseLong(name.substring(s, e));
- }
-
- /* return name of file used, or memory buffer sentinel value.
- * The return value is used to delete the file/buffer later. */
- public synchronized ReportBatch getFirstBatch() throws IOException {
- final boolean dirEmpty = isDirEmpty();
- final int currentReportsCount = mCurrentReports.reports.size();
-
- if (dirEmpty && currentReportsCount < 1) {
- return null;
- }
-
- mReportBatchIterator = new ReportBatchIterator(mFileList);
-
- if (currentReportsCount > 0) {
- final String filename = MEMORY_BUFFER_NAME;
- final byte[] data = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes());
- final int wifiCount = mCurrentReports.wifiCount;
- final int cellCount = mCurrentReports.cellCount;
- clearCurrentReports();
- final ReportBatch result = new ReportBatch(filename, data, currentReportsCount, wifiCount, cellCount);
- mCurrentReportsSendBuffer = result;
- return result;
- } else {
- return getNextBatch();
- }
- }
-
- private void clearCurrentReports() {
- mCurrentReports.reports.clear();
- mCurrentReports.wifiCount = mCurrentReports.cellCount = 0;
- }
-
- public synchronized ReportBatch getNextBatch() throws IOException {
- if (mReportBatchIterator == null) {
- return null;
- }
-
- mReportBatchIterator.currentIndex++;
- if (mReportBatchIterator.currentIndex < 0 ||
- mReportBatchIterator.currentIndex > mReportBatchIterator.fileList.mFiles.length - 1) {
- return null;
- }
-
- final File f = mReportBatchIterator.fileList.mFiles[mReportBatchIterator.currentIndex];
- final String filename = f.getName();
- final int reportCount = (int) getLongFromFilename(f.getName(), SEP_REPORT_COUNT);
- final int wifiCount = (int) getLongFromFilename(f.getName(), SEP_WIFI_COUNT);
- final int cellCount = (int) getLongFromFilename(f.getName(), SEP_CELL_COUNT);
- final byte[] data = readFile(f);
- return new ReportBatch(filename, data, reportCount, wifiCount, cellCount);
- }
-
- private File createFile(int reportCount, int wifiCount, int cellCount) {
- final long time = System.currentTimeMillis();
- final String name = FILENAME_PREFIX +
- SEP_TIME_MS + time +
- SEP_REPORT_COUNT + reportCount +
- SEP_WIFI_COUNT + wifiCount +
- SEP_CELL_COUNT + cellCount + ".gz";
- return new File(mReportsDir, name);
- }
-
- public synchronized long getOldestBatchTimeMs() {
- if (isDirEmpty()) {
- return 0;
- }
-
- long oldest = Long.MAX_VALUE;
- for (File f : mFileList.mFiles) {
- final long t = getLongFromFilename(f.getName(), SEP_TIME_MS);
- if (t < oldest) {
- oldest = t;
- }
- }
- return oldest;
- }
-
- public synchronized void saveCurrentReportsSendBufferToDisk() throws IOException {
- if (mCurrentReportsSendBuffer == null || mCurrentReportsSendBuffer.reportCount < 1) {
- return;
- }
-
- saveToDisk(mCurrentReportsSendBuffer.data,
- mCurrentReportsSendBuffer.reportCount,
- mCurrentReportsSendBuffer.wifiCount,
- mCurrentReportsSendBuffer.cellCount);
- mCurrentReportsSendBuffer = null;
- }
-
- private void saveToDisk(byte[] bytes, int reportCount, int wifiCount, int cellCount)
- throws IOException {
- if (mFileList.mFilesOnDiskBytes > mMaxBytesDiskStorage) {
- return;
- }
-
- final FileOutputStream fos = new FileOutputStream(createFile(reportCount, wifiCount, cellCount));
- try {
- fos.write(bytes);
- } finally {
- fos.close();
- }
- mFileList.update(mReportsDir);
- }
-
- private String finalizeReports(ArrayList<String> reports) {
- final String kPrefix = "{\"items\":[";
- final String kSuffix = "]}";
- final StringBuilder sb = new StringBuilder(kPrefix);
- String sep = "";
- final String separator = ",";
- if (reports != null) {
- for(String s: reports) {
- sb.append(sep).append(s);
- sep = separator;
- }
- }
-
- final String result = sb.append(kSuffix).toString();
- return result;
- }
-
- public synchronized void saveCurrentReportsToDisk() throws IOException {
- saveCurrentReportsSendBufferToDisk();
- if (mCurrentReports.reports.size() < 1) {
- return;
- }
- final byte[] bytes = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes());
- saveToDisk(bytes, mCurrentReports.reports.size(), mCurrentReports.wifiCount, mCurrentReports.cellCount);
- clearCurrentReports();
- }
-
- public synchronized void insert(String report, int wifiCount, int cellCount) throws IOException {
- notifyStorageIsEmpty(false);
-
- if (mFlushMemoryBuffersToDiskTimer != null) {
- mFlushMemoryBuffersToDiskTimer.cancel();
- mFlushMemoryBuffersToDiskTimer = null;
- }
-
- mCurrentReports.reports.add(report);
- mCurrentReports.wifiCount += wifiCount;
- mCurrentReports.cellCount += cellCount;
-
- if (mCurrentReports.reports.size() >= MAX_REPORTS_IN_MEMORY) {
- // save to disk
- saveCurrentReportsToDisk();
- } else {
- // Schedule a timer to flush to disk after a few mins.
- // If collection stops and wifi not available for uploading, the memory buffer is flushed to disk.
- final int kMillis = 1000 * 60 * 3;
- mFlushMemoryBuffersToDiskTimer = new Timer();
- mFlushMemoryBuffersToDiskTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- try {
- saveCurrentReportsToDisk();
- } catch (IOException ex) {
- Log.e(LOG_TAG, "mFlushMemoryBuffersToDiskTimer exception" + ex);
- }
- }
- }, kMillis);
- }
- }
-
- public synchronized void deleteAll() {
- if (mFileList.mFiles == null) {
- return;
- }
-
- for (File f : mFileList.mFiles) {
- f.delete();
- }
- mFileList.update(mReportsDir);
- }
-
- private void notifyStorageIsEmpty(boolean isEmpty) {
- if (mTracker != null) {
- mTracker.notifyStorageStateEmpty(isEmpty);
- }
- }
-
- public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
- mPersistedOnDiskUploadStats.incrementSyncStats(bytesSent, reports, cells, wifis);
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/PersistedStats.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/PersistedStats.java
deleted file mode 100644
index 79c8e59d1..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/PersistedStats.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/* 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.datahandling;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.utils.TelemetryWrapper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
-
-class PersistedStats {
- private final File mStatsFile;
-
- public PersistedStats(String baseDir) {
- mStatsFile = new File(baseDir, "upload_stats.ini");
- }
-
- public synchronized Properties readSyncStats() throws IOException {
- if (!mStatsFile.exists()) {
- return new Properties();
- }
-
- final FileInputStream input = new FileInputStream(mStatsFile);
- try {
- final Properties props = new Properties();
- props.load(input);
- return props;
- } finally {
- input.close();
- }
- }
-
- public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
- if (reports + cells + wifis < 1) {
- return;
- }
-
- final Properties properties = readSyncStats();
- final long time = System.currentTimeMillis();
- final long lastUploadTime = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, "0"));
- final long storedObsPerDay = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_PER_DAY, "0"));
- long observationsToday = reports;
- if (lastUploadTime > 0) {
- long dayLastUploaded = TimeUnit.MILLISECONDS.toDays(lastUploadTime);
- long dayDiff = TimeUnit.MILLISECONDS.toDays(time) - dayLastUploaded;
- if (dayDiff > 0) {
- // send value of store obs per day
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_OBSERVATIONS_PER_DAY,
- Long.valueOf(storedObsPerDay / dayDiff).intValue());
- } else {
- observationsToday += storedObsPerDay;
- }
- }
-
- writeSyncStats(time,
- Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_BYTES_SENT, "0")) + bytesSent,
- Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, "0")) + reports,
- Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_CELLS_SENT, "0")) + cells,
- Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, "0")) + wifis,
- observationsToday);
-
-
- final long lastUploadMs = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, "0"));
- final int timeDiffSec = Long.valueOf((time - lastUploadMs) / 1000).intValue();
- if (lastUploadMs > 0 && timeDiffSec > 0) {
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_UPLOADS_SEC, timeDiffSec);
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_BYTES_UPLOADED_PER_SEC, Long.valueOf(bytesSent).intValue() / timeDiffSec);
- }
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_BYTES_PER_UPLOAD, Long.valueOf(bytesSent).intValue());
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_OBSERVATIONS_PER_UPLOAD, Long.valueOf(reports).intValue());
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_WIFIS_PER_UPLOAD, Long.valueOf(wifis).intValue());
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_CELLS_PER_UPLOAD, Long.valueOf(cells).intValue());
- }
-
- public synchronized void writeSyncStats(long time, long bytesSent, long totalObs,
- long totalCells, long totalWifis, long obsPerDay) throws IOException {
- final FileOutputStream out = new FileOutputStream(mStatsFile);
- try {
- final Properties props = new Properties();
- props.setProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, String.valueOf(time));
- props.setProperty(DataStorageContract.Stats.KEY_BYTES_SENT, String.valueOf(bytesSent));
- props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, String.valueOf(totalObs));
- props.setProperty(DataStorageContract.Stats.KEY_CELLS_SENT, String.valueOf(totalCells));
- props.setProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, String.valueOf(totalWifis));
- props.setProperty(DataStorageContract.Stats.KEY_VERSION, String.valueOf(DataStorageContract.Stats.VERSION_CODE));
- props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_PER_DAY, String.valueOf(obsPerDay));
- props.store(out, null);
- } finally {
- out.close();
- }
- }
-
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java
deleted file mode 100644
index 4f47e3302..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/* 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.datahandling;
-
-import android.location.Location;
-import android.net.wifi.ScanResult;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.TelephonyManager;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellInfo;
-
-public final class StumblerBundle implements Parcelable {
- private final int mPhoneType;
- private final Location mGpsPosition;
- private final Map<String, ScanResult> mWifiData;
- private final Map<String, CellInfo> mCellData;
- private float mPressureHPA;
-
-
- public void wasSent() {
- mGpsPosition.setTime(System.currentTimeMillis());
- mWifiData.clear();
- mCellData.clear();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- Bundle wifiBundle = new Bundle(ScanResult.class.getClassLoader());
- Collection<String> scans = mWifiData.keySet();
- for (String s : scans) {
- wifiBundle.putParcelable(s, mWifiData.get(s));
- }
-
- Bundle cellBundle = new Bundle(CellInfo.class.getClassLoader());
- Collection<String> cells = mCellData.keySet();
- for (String c : cells) {
- cellBundle.putParcelable(c, mCellData.get(c));
- }
-
- out.writeBundle(wifiBundle);
- out.writeBundle(cellBundle);
- out.writeParcelable(mGpsPosition, 0);
- out.writeInt(mPhoneType);
- }
-
- public static final Parcelable.Creator<StumblerBundle> CREATOR
- = new Parcelable.Creator<StumblerBundle>() {
- @Override
- public StumblerBundle createFromParcel(Parcel in) {
- return new StumblerBundle(in);
- }
-
- @Override
- public StumblerBundle[] newArray(int size) {
- return new StumblerBundle[size];
- }
- };
-
- private StumblerBundle(Parcel in) {
- mWifiData = new HashMap<String, ScanResult>();
- mCellData = new HashMap<String, CellInfo>();
-
- Bundle wifiBundle = in.readBundle(ScanResult.class.getClassLoader());
- Bundle cellBundle = in.readBundle(CellInfo.class.getClassLoader());
-
- Collection<String> scans = wifiBundle.keySet();
- for (String s : scans) {
- mWifiData.put(s, (ScanResult) wifiBundle.get(s));
- }
-
- Collection<String> cells = cellBundle.keySet();
- for (String c : cells) {
- mCellData.put(c, (CellInfo) cellBundle.get(c));
- }
-
- mGpsPosition = in.readParcelable(Location.class.getClassLoader());
- mPhoneType = in.readInt();
- }
-
- public StumblerBundle(Location position, int phoneType) {
- mGpsPosition = position;
- mPhoneType = phoneType;
- mWifiData = new HashMap<String, ScanResult>();
- mCellData = new HashMap<String, CellInfo>();
- }
-
- public Location getGpsPosition() {
- return mGpsPosition;
- }
-
- public Map<String, ScanResult> getWifiData() {
- return mWifiData;
- }
-
- public Map<String, CellInfo> getCellData() {
- return mCellData;
- }
-
- public JSONObject toMLSJSON() throws JSONException {
- JSONObject item = new JSONObject();
-
- item.put(DataStorageContract.ReportsColumns.TIME, mGpsPosition.getTime());
- item.put(DataStorageContract.ReportsColumns.LAT, Math.floor(mGpsPosition.getLatitude() * 1.0E6) / 1.0E6);
- item.put(DataStorageContract.ReportsColumns.LON, Math.floor(mGpsPosition.getLongitude() * 1.0E6) / 1.0E6);
-
- item.put(DataStorageContract.ReportsColumns.HEADING, mGpsPosition.getBearing());
- item.put(DataStorageContract.ReportsColumns.SPEED, mGpsPosition.getSpeed());
- if (mPressureHPA != 0.0) {
- item.put(DataStorageContract.ReportsColumns.PRESSURE, mPressureHPA);
- }
-
-
- if (mGpsPosition.hasAccuracy()) {
- item.put(DataStorageContract.ReportsColumns.ACCURACY, (int) Math.ceil(mGpsPosition.getAccuracy()));
- }
-
- if (mGpsPosition.hasAltitude()) {
- item.put(DataStorageContract.ReportsColumns.ALTITUDE, Math.round(mGpsPosition.getAltitude()));
- }
-
- if (mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
- item.put(DataStorageContract.ReportsColumns.RADIO, "gsm");
- } else if (mPhoneType == TelephonyManager.PHONE_TYPE_CDMA) {
- item.put(DataStorageContract.ReportsColumns.RADIO, "cdma");
- } else {
- // issue #598. investigate this case further in future
- item.put(DataStorageContract.ReportsColumns.RADIO, "");
- }
-
- JSONArray cellJSON = new JSONArray();
- for (CellInfo c : mCellData.values()) {
- JSONObject obj = c.toJSONObject();
- cellJSON.put(obj);
- }
-
- item.put(DataStorageContract.ReportsColumns.CELL, cellJSON);
- item.put(DataStorageContract.ReportsColumns.CELL_COUNT, cellJSON.length());
-
- JSONArray wifis = new JSONArray();
-
- long gpsTimeSinceBootInMS = 0;
-
- if (Build.VERSION.SDK_INT >= 17) {
- gpsTimeSinceBootInMS = mGpsPosition.getElapsedRealtimeNanos() / 1000000;
- }
-
- for (ScanResult s : mWifiData.values()) {
- JSONObject wifiEntry = new JSONObject();
- wifiEntry.put("key", s.BSSID);
- wifiEntry.put("frequency", s.frequency);
- wifiEntry.put("signal", s.level);
-
- if (Build.VERSION.SDK_INT >= 17) {
- long wifiTimeSinceBootInMS = (s.timestamp / 1000);
- long ageMS = wifiTimeSinceBootInMS - gpsTimeSinceBootInMS;
- wifiEntry.put("age", ageMS);
- }
-
- wifis.put(wifiEntry);
- }
- item.put(DataStorageContract.ReportsColumns.WIFI, wifis);
- item.put(DataStorageContract.ReportsColumns.WIFI_COUNT, wifis.length());
-
- return item;
- }
-
-
- public void addPressure(float hPa) {
- mPressureHPA = hPa;
- }
-
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java
deleted file mode 100644
index 218b97af4..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/* 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.scanners;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.Intent;
-import android.location.GpsSatellite;
-import android.location.GpsStatus;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
-import org.mozilla.mozstumbler.service.Prefs;
-import org.mozilla.mozstumbler.service.utils.TelemetryWrapper;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class GPSScanner implements LocationListener {
- public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".GPSScanner.";
- public static final String ACTION_GPS_UPDATED = ACTION_BASE + "GPS_UPDATED";
- public static final String ACTION_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
- public static final String SUBJECT_NEW_STATUS = "new_status";
- public static final String SUBJECT_LOCATION_LOST = "location_lost";
- public static final String SUBJECT_NEW_LOCATION = "new_location";
- public static final String NEW_STATUS_ARG_FIXES = "fixes";
- public static final String NEW_STATUS_ARG_SATS = "sats";
- public static final String NEW_LOCATION_ARG_LOCATION = "location";
-
- private static final String LOG_TAG = AppGlobals.makeLogTag(GPSScanner.class.getSimpleName());
- private static final int MIN_SAT_USED_IN_FIX = 3;
- private static final long ACTIVE_MODE_GPS_MIN_UPDATE_TIME_MS = 1000;
- private static final float ACTIVE_MODE_GPS_MIN_UPDATE_DISTANCE_M = 10;
- private static final long PASSIVE_GPS_MIN_UPDATE_FREQ_MS = 3000;
- private static final float PASSIVE_GPS_MOVEMENT_MIN_DELTA_M = 30;
-
- private final LocationBlockList mBlockList = new LocationBlockList();
- private final Context mContext;
- private GpsStatus.Listener mGPSListener;
- private int mLocationCount;
- private Location mLocation = new Location("internal");
- private boolean mAutoGeofencing;
- private boolean mIsPassiveMode;
- private long mTelemetry_lastStartedMs;
- private final ScanManager mScanManager;
-
- public GPSScanner(Context context, ScanManager scanManager) {
- mContext = context;
- mScanManager = scanManager;
- }
-
- public void start(final ActiveOrPassiveStumbling stumblingMode) {
- mIsPassiveMode = (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
- if (mIsPassiveMode ) {
- startPassiveMode();
- } else {
- startActiveMode();
- }
- }
-
- private boolean isGpsAvailable(LocationManager locationManager) {
- if (locationManager == null ||
- locationManager.getProvider(LocationManager.GPS_PROVIDER) == null) {
- String msg = "No GPS available, scanning not started.";
- Log.d(LOG_TAG, msg);
- AppGlobals.guiLogError(msg);
- return false;
- }
- return true;
- }
-
- @SuppressLint("MissingPermission") // Permissions are explicitly checked for in StumblerService.onHandleIntent()
- private void startPassiveMode() {
- LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- if (!isGpsAvailable(locationManager)) {
- return;
- }
-
- locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
-
- final int timeDiffSec = Long.valueOf((System.currentTimeMillis() - mTelemetry_lastStartedMs) / 1000).intValue();
- if (mTelemetry_lastStartedMs > 0 && timeDiffSec > 0) {
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_STARTS_SEC, timeDiffSec);
- }
- mTelemetry_lastStartedMs = System.currentTimeMillis();
- }
-
- @SuppressLint("MissingPermission") // Permissions are explicitly checked for in StumblerService.onHandleIntent()
- private void startActiveMode() {
- LocationManager lm = getLocationManager();
- if (!isGpsAvailable(lm)) {
- return;
- }
-
- lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
- ACTIVE_MODE_GPS_MIN_UPDATE_TIME_MS,
- ACTIVE_MODE_GPS_MIN_UPDATE_DISTANCE_M,
- this);
-
- reportLocationLost();
- mGPSListener = new GpsStatus.Listener() {
- @Override
- public void onGpsStatusChanged(int event) {
- if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
- GpsStatus status = getLocationManager().getGpsStatus(null);
- Iterable<GpsSatellite> sats = status.getSatellites();
-
- int satellites = 0;
- int fixes = 0;
-
- for (GpsSatellite sat : sats) {
- satellites++;
- if (sat.usedInFix()) {
- fixes++;
- }
- }
- reportNewGpsStatus(fixes, satellites);
- if (fixes < MIN_SAT_USED_IN_FIX) {
- reportLocationLost();
- }
-
- if (AppGlobals.isDebug) {
- Log.v(LOG_TAG, "onGpsStatusChange - satellites: " + satellites + " fixes: " + fixes);
- }
- } else if (event == GpsStatus.GPS_EVENT_STOPPED) {
- reportLocationLost();
- }
- }
- };
-
- lm.addGpsStatusListener(mGPSListener);
- }
-
- @SuppressLint("MissingPermission") // Permissions are explicitly checked for in StumblerService.onHandleIntent()
- public void stop() {
- LocationManager lm = getLocationManager();
- lm.removeUpdates(this);
- reportLocationLost();
-
- if (mGPSListener != null) {
- lm.removeGpsStatusListener(mGPSListener);
- mGPSListener = null;
- }
- }
-
- public int getLocationCount() {
- return mLocationCount;
- }
-
- public double getLatitude() {
- return mLocation.getLatitude();
- }
-
- public double getLongitude() {
- return mLocation.getLongitude();
- }
-
- public Location getLocation() {
- return mLocation;
- }
-
- public void checkPrefs() {
- if (mBlockList != null) {
- mBlockList.updateBlocks();
- }
-
- Prefs prefs = Prefs.getInstanceWithoutContext();
- if (prefs == null) {
- return;
- }
- mAutoGeofencing = prefs.getGeofenceHere();
- }
-
- public boolean isGeofenced() {
- return (mBlockList != null) && mBlockList.isGeofenced();
- }
-
- private void sendToLogActivity(String msg) {
- AppGlobals.guiLogInfo(msg, "#33ccff", false);
- }
-
- @Override
- public void onLocationChanged(Location location) {
- if (location == null) { // TODO: is this even possible??
- reportLocationLost();
- return;
- }
-
- String logMsg = (mIsPassiveMode)? "[Passive] " : "[Active] ";
-
- String provider = location.getProvider();
- if (!provider.toLowerCase().contains("gps")) {
- Log.d(LOG_TAG, "Discard fused/network location.");
- // only interested in GPS locations
- return;
- }
-
- final long timeDeltaMs = location.getTime() - mLocation.getTime();
-
- // Seem to get greater likelihood of non-fused location with higher update freq.
- // Check dist and time threshold here, not set on the listener.
- if (mIsPassiveMode) {
- final boolean hasMoved = location.distanceTo(mLocation) > PASSIVE_GPS_MOVEMENT_MIN_DELTA_M;
-
- if (timeDeltaMs < PASSIVE_GPS_MIN_UPDATE_FREQ_MS || !hasMoved) {
- return;
- }
- }
-
- Date date = new Date(location.getTime());
- SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
- String time = formatter.format(date);
- logMsg += String.format("%s Coord: %.4f,%.4f, Acc: %.0f, Speed: %.0f, Alt: %.0f, Bearing: %.1f", time, location.getLatitude(),
- location.getLongitude(), location.getAccuracy(), location.getSpeed(), location.getAltitude(), location.getBearing());
- sendToLogActivity(logMsg);
-
- if (mBlockList.contains(location)) {
- reportLocationLost();
- return;
- }
-
- mLocation = location;
-
- if (!mAutoGeofencing) {
- reportNewLocationReceived(location);
- }
- mLocationCount++;
-
- if (mIsPassiveMode) {
- mScanManager.newPassiveGpsLocation();
- }
-
- if (timeDeltaMs > 0) {
- TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC,
- Long.valueOf(timeDeltaMs).intValue() / 1000);
- }
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- if (LocationManager.GPS_PROVIDER.equals(provider)) {
- reportLocationLost();
- }
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- if ((status != LocationProvider.AVAILABLE) &&
- (LocationManager.GPS_PROVIDER.equals(provider))) {
- reportLocationLost();
- }
- }
-
- private LocationManager getLocationManager() {
- return (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- }
-
- private void reportNewLocationReceived(Location location) {
- Intent i = new Intent(ACTION_GPS_UPDATED);
- i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_NEW_LOCATION);
- i.putExtra(NEW_LOCATION_ARG_LOCATION, location);
- i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
- LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
- }
-
- private void reportLocationLost() {
- Intent i = new Intent(ACTION_GPS_UPDATED);
- i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_LOCATION_LOST);
- i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
- LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
- }
-
- private void reportNewGpsStatus(int fixes, int sats) {
- Intent i = new Intent(ACTION_GPS_UPDATED);
- i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_NEW_STATUS);
- i.putExtra(NEW_STATUS_ARG_FIXES, fixes);
- i.putExtra(NEW_STATUS_ARG_SATS, sats);
- i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
- LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java
deleted file mode 100644
index c3cba7b45..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/* 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.scanners;
-
-import android.location.Location;
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.Prefs;
-
-public final class LocationBlockList {
- private static final String LOG_TAG = AppGlobals.makeLogTag(LocationBlockList.class.getSimpleName());
- private static final double MAX_ALTITUDE = 8848; // Mount Everest's altitude in meters
- private static final double MIN_ALTITUDE = -418; // Dead Sea's altitude in meters
- private static final float MAX_SPEED = 340.29f; // Mach 1 in meters/second
- private static final float MIN_ACCURACY = 500; // meter radius
- private static final long MIN_TIMESTAMP = 946684801; // 2000-01-01 00:00:01
- private static final double GEOFENCE_RADIUS = 0.01; // .01 degrees is approximately 1km
- private static final long MILLISECONDS_PER_DAY = 86400000;
-
- private Location mBlockedLocation;
- private boolean mGeofencingEnabled;
- private boolean mIsGeofenced = false;
-
- public LocationBlockList() {
- updateBlocks();
- }
-
- public void updateBlocks() {
- Prefs prefs = Prefs.getInstanceWithoutContext();
- if (prefs == null) {
- return;
- }
- mBlockedLocation = prefs.getGeofenceLocation();
- mGeofencingEnabled = prefs.getGeofenceEnabled();
- }
-
- public boolean contains(Location location) {
- final float inaccuracy = location.getAccuracy();
- final double altitude = location.getAltitude();
- final float bearing = location.getBearing();
- final double latitude = location.getLatitude();
- final double longitude = location.getLongitude();
- final float speed = location.getSpeed();
- final long timestamp = location.getTime();
- final long tomorrow = System.currentTimeMillis() + MILLISECONDS_PER_DAY;
-
- boolean block = false;
- mIsGeofenced = false;
-
- if (latitude == 0 && longitude == 0) {
- block = true;
- Log.w(LOG_TAG, "Bogus latitude,longitude: 0,0");
- } else {
- if (latitude < -90 || latitude > 90) {
- block = true;
- Log.w(LOG_TAG, "Bogus latitude: " + latitude);
- }
-
- if (longitude < -180 || longitude > 180) {
- block = true;
- Log.w(LOG_TAG, "Bogus longitude: " + longitude);
- }
- }
-
- if (location.hasAccuracy() && (inaccuracy < 0 || inaccuracy > MIN_ACCURACY)) {
- block = true;
- Log.w(LOG_TAG, "Insufficient accuracy: " + inaccuracy + " meters");
- }
-
- if (location.hasAltitude() && (altitude < MIN_ALTITUDE || altitude > MAX_ALTITUDE)) {
- block = true;
- Log.w(LOG_TAG, "Bogus altitude: " + altitude + " meters");
- }
-
- if (location.hasBearing() && (bearing < 0 || bearing > 360)) {
- block = true;
- Log.w(LOG_TAG, "Bogus bearing: " + bearing + " degrees");
- }
-
- if (location.hasSpeed() && (speed < 0 || speed > MAX_SPEED)) {
- block = true;
- Log.w(LOG_TAG, "Bogus speed: " + speed + " meters/second");
- }
-
- if (timestamp < MIN_TIMESTAMP || timestamp > tomorrow) {
- block = true;
- Log.w(LOG_TAG, "Bogus timestamp: " + timestamp);
- }
-
- if (mGeofencingEnabled &&
- Math.abs(location.getLatitude() - mBlockedLocation.getLatitude()) < GEOFENCE_RADIUS &&
- Math.abs(location.getLongitude() - mBlockedLocation.getLongitude()) < GEOFENCE_RADIUS) {
- block = true;
- mIsGeofenced = true;
- }
-
- return block;
- }
-
- public boolean isGeofenced() {
- return mIsGeofenced;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java
deleted file mode 100644
index 60d7c8f1c..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/* 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.scanners;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.Location;
-import android.os.BatteryManager;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
-import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
-import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
-import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
-
-import java.util.Date;
-import java.util.Timer;
-import java.util.TimerTask;
-
-public class ScanManager {
- private static final String LOG_TAG = AppGlobals.makeLogTag(ScanManager.class.getSimpleName());
- private Timer mPassiveModeFlushTimer;
- private Context mContext;
- private boolean mIsScanning;
- private GPSScanner mGPSScanner;
- private WifiScanner mWifiScanner;
- private CellScanner mCellScanner;
- private ActiveOrPassiveStumbling mStumblingMode = ActiveOrPassiveStumbling.ACTIVE_STUMBLING;
-
- public ScanManager() {
- }
-
- private boolean isBatteryLow() {
- Intent intent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- if (intent == null) {
- return false;
- }
-
- int rawLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
- int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
- boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING);
- int level = Math.round(rawLevel * scale/100.0f);
-
- final int kMinBatteryPct = 15;
- return !isCharging && level < kMinBatteryPct;
- }
-
- public void newPassiveGpsLocation() {
- if (isBatteryLow()) {
- return;
- }
-
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "New passive location");
- }
-
- mWifiScanner.start(ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
- mCellScanner.start(ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
-
- // how often to flush a leftover bundle to the reports table
- // If there is a bundle, and nothing happens for 10sec, then flush it
- final int flushRate_ms = 10000;
-
- if (mPassiveModeFlushTimer != null) {
- mPassiveModeFlushTimer.cancel();
- }
-
- Date when = new Date();
- when.setTime(when.getTime() + flushRate_ms);
- mPassiveModeFlushTimer = new Timer();
- mPassiveModeFlushTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- Intent flush = new Intent(Reporter.ACTION_FLUSH_TO_BUNDLE);
- LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(flush);
- }
- }, when);
- }
-
- public void setPassiveMode(boolean on) {
- mStumblingMode = (on)? ActiveOrPassiveStumbling.PASSIVE_STUMBLING :
- ActiveOrPassiveStumbling.ACTIVE_STUMBLING;
- }
-
- public boolean isPassiveMode() {
- return ActiveOrPassiveStumbling.PASSIVE_STUMBLING == mStumblingMode;
- }
-
- public void startScanning(Context context) {
- if (mIsScanning) {
- return;
- }
-
- mContext = context.getApplicationContext();
- if (mContext == null) {
- Log.w(LOG_TAG, "No app context available.");
- return;
- }
-
- if (mGPSScanner == null) {
- mGPSScanner = new GPSScanner(context, this);
- mWifiScanner = new WifiScanner(context);
- mCellScanner = new CellScanner(context);
- }
-
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "Scanning started...");
- }
-
- mGPSScanner.start(mStumblingMode);
- if (mStumblingMode == ActiveOrPassiveStumbling.ACTIVE_STUMBLING) {
- mWifiScanner.start(mStumblingMode);
- mCellScanner.start(mStumblingMode);
- // in passive mode, these scans are started by passive gps notifications
- }
- mIsScanning = true;
- }
-
- public boolean stopScanning() {
- if (!mIsScanning) {
- return false;
- }
-
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "Scanning stopped");
- }
-
- mGPSScanner.stop();
- mWifiScanner.stop();
- mCellScanner.stop();
-
- mIsScanning = false;
- return true;
- }
-
- public void setWifiBlockList(WifiBlockListInterface list) {
- WifiScanner.setWifiBlockList(list);
- }
-
- public boolean isScanning() {
- return mIsScanning;
- }
-
- public int getAPCount() {
- return (mWifiScanner == null)? 0 : mWifiScanner.getAPCount();
- }
-
- public int getVisibleAPCount() {
- return (mWifiScanner == null)? 0 :mWifiScanner.getVisibleAPCount();
- }
-
- public int getWifiStatus() {
- return (mWifiScanner == null)? 0 : mWifiScanner.getStatus();
- }
-
- public int getCellInfoCount() {
- return (mCellScanner == null)? 0 :mCellScanner.getCellInfoCount();
- }
-
- public int getLocationCount() {
- return (mGPSScanner == null)? 0 : mGPSScanner.getLocationCount();
- }
-
- public double getLatitude() {
- return (mGPSScanner == null)? 0.0 : mGPSScanner.getLatitude();
- }
-
- public double getLongitude() {
- return (mGPSScanner == null)? 0.0 : mGPSScanner.getLongitude();
- }
-
- public Location getLocation() {
- return (mGPSScanner == null)? new Location("null") : mGPSScanner.getLocation();
- }
-
- public void checkPrefs() {
- if (mGPSScanner != null) {
- mGPSScanner.checkPrefs();
- }
- }
-
- public boolean isGeofenced() {
- return (mGPSScanner != null) && mGPSScanner.isGeofenced();
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java
deleted file mode 100644
index eed61d8bb..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/* 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.scanners;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiManager.WifiLock;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.stumblerthread.blocklist.BSSIDBlockList;
-import org.mozilla.mozstumbler.service.stumblerthread.blocklist.SSIDBlockList;
-import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
-import org.mozilla.mozstumbler.service.Prefs;
-import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
-
-public class WifiScanner extends BroadcastReceiver {
- public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".WifiScanner.";
- public static final String ACTION_WIFIS_SCANNED = ACTION_BASE + "WIFIS_SCANNED";
- public static final String ACTION_WIFIS_SCANNED_ARG_RESULTS = "scan_results";
- public static final String ACTION_WIFIS_SCANNED_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
-
- public static final int STATUS_IDLE = 0;
- public static final int STATUS_ACTIVE = 1;
- public static final int STATUS_WIFI_DISABLED = -1;
-
- private static final String LOG_TAG = AppGlobals.makeLogTag(WifiScanner.class.getSimpleName());
- private static final long WIFI_MIN_UPDATE_TIME = 5000; // milliseconds
-
- private boolean mStarted;
- private final Context mContext;
- private WifiLock mWifiLock;
- private Timer mWifiScanTimer;
- private final Set<String> mAPs = Collections.synchronizedSet(new HashSet<String>());
- private final AtomicInteger mVisibleAPs = new AtomicInteger();
-
- /* Testing */
- public static boolean sIsTestMode;
- public List<ScanResult> mTestModeFakeScanResults = new ArrayList<ScanResult>();
- public Set<String> getAccessPoints(android.test.AndroidTestCase restrictedAccessor) { return mAPs; }
- /* ------- */
-
- public WifiScanner(Context c) {
- mContext = c;
- }
-
- private boolean isWifiEnabled() {
- return (sIsTestMode) || getWifiManager().isWifiEnabled();
- }
-
- private List<ScanResult> getScanResults() {
- WifiManager manager = getWifiManager();
- if (manager == null) {
- return null;
- }
- return getWifiManager().getScanResults();
- }
-
-
- public synchronized void start(final ActiveOrPassiveStumbling stumblingMode) {
- Prefs prefs = Prefs.getInstanceWithoutContext();
- if (mStarted || prefs == null) {
- return;
- }
- mStarted = true;
-
- boolean scanAlways = prefs.getWifiScanAlways();
-
- if (scanAlways || isWifiEnabled()) {
- activatePeriodicScan(stumblingMode);
- }
-
- IntentFilter i = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- if (!scanAlways) i.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- mContext.registerReceiver(this, i);
- }
-
- public synchronized void stop() {
- if (mStarted) {
- mContext.unregisterReceiver(this);
- }
- deactivatePeriodicScan();
- mStarted = false;
- }
-
- @Override
- public void onReceive(Context c, Intent intent) {
- String action = intent.getAction();
-
- if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
- if (isWifiEnabled()) {
- activatePeriodicScan(ActiveOrPassiveStumbling.ACTIVE_STUMBLING);
- } else {
- deactivatePeriodicScan();
- }
- } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
- final List<ScanResult> scanResultList = getScanResults();
- if (scanResultList == null) {
- return;
- }
- final ArrayList<ScanResult> scanResults = new ArrayList<ScanResult>();
- for (ScanResult scanResult : scanResultList) {
- scanResult.BSSID = BSSIDBlockList.canonicalizeBSSID(scanResult.BSSID);
- if (shouldLog(scanResult)) {
- scanResults.add(scanResult);
- mAPs.add(scanResult.BSSID);
- }
- }
- mVisibleAPs.set(scanResults.size());
- reportScanResults(scanResults);
- }
- }
-
- public static void setWifiBlockList(WifiBlockListInterface blockList) {
- BSSIDBlockList.setFilterList(blockList.getBssidOuiList());
- SSIDBlockList.setFilterLists(blockList.getSsidPrefixList(), blockList.getSsidSuffixList());
- }
-
- public int getAPCount() {
- return mAPs.size();
- }
-
- public int getVisibleAPCount() {
- return mVisibleAPs.get();
- }
-
- public synchronized int getStatus() {
- if (!mStarted) {
- return STATUS_IDLE;
- }
- if (mWifiScanTimer == null) {
- return STATUS_WIFI_DISABLED;
- }
- return STATUS_ACTIVE;
- }
-
- private synchronized void activatePeriodicScan(final ActiveOrPassiveStumbling stumblingMode) {
- if (mWifiScanTimer != null) {
- return;
- }
-
- if (AppGlobals.isDebug) {
- Log.v(LOG_TAG, "Activate Periodic Scan");
- }
-
- mWifiLock = getWifiManager().createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "MozStumbler");
- mWifiLock.acquire();
-
- // Ensure that we are constantly scanning for new access points.
- mWifiScanTimer = new Timer();
- mWifiScanTimer.schedule(new TimerTask() {
- int mPassiveScanCount;
- @Override
- public void run() {
- if (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING &&
- mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
- {
- mPassiveScanCount = 0;
- stop(); // set mWifiScanTimer to null
- return;
- }
- if (AppGlobals.isDebug) {
- Log.v(LOG_TAG, "WiFi Scanning Timer fired");
- }
- getWifiManager().startScan();
- }
- }, 0, WIFI_MIN_UPDATE_TIME);
- }
-
- private synchronized void deactivatePeriodicScan() {
- if (mWifiScanTimer == null) {
- return;
- }
-
- if (AppGlobals.isDebug) {
- Log.v(LOG_TAG, "Deactivate periodic scan");
- }
-
- mWifiLock.release();
- mWifiLock = null;
-
- mWifiScanTimer.cancel();
- mWifiScanTimer = null;
-
- mVisibleAPs.set(0);
- }
-
- public static boolean shouldLog(ScanResult scanResult) {
- if (BSSIDBlockList.contains(scanResult)) {
- return false;
- }
- if (SSIDBlockList.contains(scanResult)) {
- return false;
- }
- return true;
- }
-
- private WifiManager getWifiManager() {
- return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- }
-
- private void reportScanResults(ArrayList<ScanResult> scanResults) {
- if (scanResults.isEmpty()) {
- return;
- }
-
- Intent i = new Intent(ACTION_WIFIS_SCANNED);
- i.putParcelableArrayListExtra(ACTION_WIFIS_SCANNED_ARG_RESULTS, scanResults);
- i.putExtra(ACTION_WIFIS_SCANNED_ARG_TIME, System.currentTimeMillis());
- LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java
deleted file mode 100644
index f435dcf11..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/* 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.scanners.cellscanner;
-
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.CellLocation;
-import android.telephony.NeighboringCellInfo;
-import android.telephony.TelephonyManager;
-import android.telephony.cdma.CdmaCellLocation;
-import android.telephony.gsm.GsmCellLocation;
-import android.util.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.mozstumbler.service.AppGlobals;
-
-public class CellInfo implements Parcelable {
- private static final String LOG_TAG = AppGlobals.makeLogTag(CellInfo.class.getSimpleName());
-
- public static final String RADIO_GSM = "gsm";
- public static final String RADIO_CDMA = "cdma";
- public static final String RADIO_WCDMA = "wcdma";
-
- public static final String CELL_RADIO_GSM = "gsm";
- public static final String CELL_RADIO_UMTS = "umts";
- public static final String CELL_RADIO_CDMA = "cdma";
- public static final String CELL_RADIO_LTE = "lte";
-
- public static final int UNKNOWN_CID = -1;
- public static final int UNKNOWN_SIGNAL = -1000;
-
- public static final Parcelable.Creator<CellInfo> CREATOR
- = new Parcelable.Creator<CellInfo>() {
- @Override
- public CellInfo createFromParcel(Parcel in) {
- return new CellInfo(in);
- }
-
- @Override
- public CellInfo[] newArray(int size) {
- return new CellInfo[size];
- }
- };
-
- private String mRadio;
- private String mCellRadio;
-
- private int mMcc;
- private int mMnc;
- private int mCid;
- private int mLac;
- private int mSignal;
- private int mAsu;
- private int mTa;
- private int mPsc;
-
- public CellInfo(int phoneType) {
- reset();
- setRadio(phoneType);
- }
-
- private CellInfo(Parcel in) {
- mRadio = in.readString();
- mCellRadio = in.readString();
- mMcc = in.readInt();
- mMnc = in.readInt();
- mCid = in.readInt();
- mLac = in.readInt();
- mSignal = in.readInt();
- mAsu = in.readInt();
- mTa = in.readInt();
- mPsc = in.readInt();
- }
-
- public boolean isCellRadioValid() {
- return mCellRadio != null && (mCellRadio.length() > 0) && !mCellRadio.equals("0");
- }
-
- public String getRadio() {
- return mRadio;
- }
-
- public String getCellRadio() {
- return mCellRadio;
- }
-
- public int getMcc() {
- return mMcc;
- }
-
- public int getMnc() {
- return mMnc;
- }
-
- public int getCid() {
- return mCid;
- }
-
- public int getLac() {
- return mLac;
- }
-
- public int getPsc() {
- return mPsc;
- }
-
- public JSONObject toJSONObject() {
- final JSONObject obj = new JSONObject();
-
- try {
- obj.put("radio", getCellRadio());
- obj.put("mcc", mMcc);
- obj.put("mnc", mMnc);
- if (mLac != UNKNOWN_CID) obj.put("lac", mLac);
- if (mCid != UNKNOWN_CID) obj.put("cid", mCid);
- if (mSignal != UNKNOWN_SIGNAL) obj.put("signal", mSignal);
- if (mAsu != UNKNOWN_SIGNAL) obj.put("asu", mAsu);
- if (mTa != UNKNOWN_CID) obj.put("ta", mTa);
- if (mPsc != UNKNOWN_CID) obj.put("psc", mPsc);
- } catch (JSONException jsonE) {
- throw new IllegalStateException(jsonE);
- }
-
- return obj;
- }
-
- public String getCellIdentity() {
- return getRadio()
- + " " + getCellRadio()
- + " " + getMcc()
- + " " + getMnc()
- + " " + getLac()
- + " " + getCid()
- + " " + getPsc();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mRadio);
- dest.writeString(mCellRadio);
- dest.writeInt(mMcc);
- dest.writeInt(mMnc);
- dest.writeInt(mCid);
- dest.writeInt(mLac);
- dest.writeInt(mSignal);
- dest.writeInt(mAsu);
- dest.writeInt(mTa);
- dest.writeInt(mPsc);
- }
-
- void reset() {
- mRadio = RADIO_GSM;
- mCellRadio = CELL_RADIO_GSM;
- mMcc = UNKNOWN_CID;
- mMnc = UNKNOWN_CID;
- mLac = UNKNOWN_CID;
- mCid = UNKNOWN_CID;
- mSignal = UNKNOWN_SIGNAL;
- mAsu = UNKNOWN_SIGNAL;
- mTa = UNKNOWN_CID;
- mPsc = UNKNOWN_CID;
- }
-
- void setRadio(int phoneType) {
- mRadio = getRadioTypeName(phoneType);
- }
-
- void setCellLocation(CellLocation cl,
- int networkType,
- String networkOperator,
- Integer gsmSignalStrength,
- Integer cdmaRssi) {
- if (cl instanceof GsmCellLocation) {
- final int lac, cid;
- final GsmCellLocation gcl = (GsmCellLocation) cl;
-
- reset();
- mCellRadio = getCellRadioTypeName(networkType);
- setNetworkOperator(networkOperator);
-
- lac = gcl.getLac();
- cid = gcl.getCid();
- if (lac >= 0) mLac = lac;
- if (cid >= 0) mCid = cid;
-
- if (Build.VERSION.SDK_INT >= 9) {
- final int psc = gcl.getPsc();
- if (psc >= 0) mPsc = psc;
- }
-
- if (gsmSignalStrength != null) {
- mAsu = gsmSignalStrength;
- }
- } else if (cl instanceof CdmaCellLocation) {
- final CdmaCellLocation cdl = (CdmaCellLocation) cl;
-
- reset();
- mCellRadio = getCellRadioTypeName(networkType);
-
- setNetworkOperator(networkOperator);
-
- mMnc = cdl.getSystemId();
-
- mLac = cdl.getNetworkId();
- mCid = cdl.getBaseStationId();
-
- if (cdmaRssi != null) {
- mSignal = cdmaRssi;
- }
- } else {
- throw new IllegalArgumentException("Unexpected CellLocation type: " + cl.getClass().getName());
- }
- }
-
- void setNeighboringCellInfo(NeighboringCellInfo nci, String networkOperator) {
- final int lac, cid, psc, rssi;
-
- reset();
- mCellRadio = getCellRadioTypeName(nci.getNetworkType());
- setNetworkOperator(networkOperator);
-
- lac = nci.getLac();
- cid = nci.getCid();
- psc = nci.getPsc();
- rssi = nci.getRssi();
-
- if (lac >= 0) mLac = lac;
- if (cid >= 0) mCid = cid;
- if (psc >= 0) mPsc = psc;
- if (rssi != NeighboringCellInfo.UNKNOWN_RSSI) mAsu = rssi;
- }
-
- void setGsmCellInfo(int mcc, int mnc, int lac, int cid, int asu) {
- mCellRadio = CELL_RADIO_GSM;
- mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
- mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
- mLac = lac != Integer.MAX_VALUE ? lac : UNKNOWN_CID;
- mCid = cid != Integer.MAX_VALUE ? cid : UNKNOWN_CID;
- mAsu = asu;
- }
-
- public void setWcmdaCellInfo(int mcc, int mnc, int lac, int cid, int psc, int asu) {
- mCellRadio = CELL_RADIO_UMTS;
- mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
- mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
- mLac = lac != Integer.MAX_VALUE ? lac : UNKNOWN_CID;
- mCid = cid != Integer.MAX_VALUE ? cid : UNKNOWN_CID;
- mPsc = psc != Integer.MAX_VALUE ? psc : UNKNOWN_CID;
- mAsu = asu;
- }
-
- /**
- * @param mcc Mobile Country Code, Integer.MAX_VALUE if unknown
- * @param mnc Mobile Network Code, Integer.MAX_VALUE if unknown
- * @param ci Cell Identity, Integer.MAX_VALUE if unknown
- * @param pci Physical Cell Id, Integer.MAX_VALUE if unknown
- * @param tac Tracking Area Code, Integer.MAX_VALUE if unknown
- * @param asu Arbitrary strength unit
- * @param ta Timing advance
- */
- void setLteCellInfo(int mcc, int mnc, int ci, int pci, int tac, int asu, int ta) {
- mCellRadio = CELL_RADIO_LTE;
- mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
- mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
- mLac = tac != Integer.MAX_VALUE ? tac : UNKNOWN_CID;
- mCid = ci != Integer.MAX_VALUE ? ci : UNKNOWN_CID;
- mPsc = pci != Integer.MAX_VALUE ? pci : UNKNOWN_CID;
- mAsu = asu;
- mTa = ta;
- }
-
- void setCdmaCellInfo(int baseStationId, int networkId, int systemId, int dbm) {
- mCellRadio = CELL_RADIO_CDMA;
- mMnc = systemId != Integer.MAX_VALUE ? systemId : UNKNOWN_CID;
- mLac = networkId != Integer.MAX_VALUE ? networkId : UNKNOWN_CID;
- mCid = baseStationId != Integer.MAX_VALUE ? baseStationId : UNKNOWN_CID;
- mSignal = dbm;
- }
-
- void setNetworkOperator(String mccMnc) {
- if (mccMnc == null || mccMnc.length() < 5 || mccMnc.length() > 8) {
- throw new IllegalArgumentException("Bad mccMnc: " + mccMnc);
- }
- mMcc = Integer.parseInt(mccMnc.substring(0, 3));
- mMnc = Integer.parseInt(mccMnc.substring(3));
- }
-
- static String getCellRadioTypeName(int networkType) {
- switch (networkType) {
- // If the network is either GSM or any high-data-rate variant of it, the radio
- // field should be specified as `gsm`. This includes `GSM`, `EDGE` and `GPRS`.
- case TelephonyManager.NETWORK_TYPE_GPRS:
- case TelephonyManager.NETWORK_TYPE_EDGE:
- return CELL_RADIO_GSM;
-
- // If the network is either UMTS or any high-data-rate variant of it, the radio
- // field should be specified as `umts`. This includes `UMTS`, `HSPA`, `HSDPA`,
- // `HSPA+` and `HSUPA`.
- case TelephonyManager.NETWORK_TYPE_UMTS:
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- return CELL_RADIO_UMTS;
-
- case TelephonyManager.NETWORK_TYPE_LTE:
- return CELL_RADIO_LTE;
-
- // If the network is either CDMA or one of the EVDO variants, the radio
- // field should be specified as `cdma`. This includes `1xRTT`, `CDMA`, `eHRPD`,
- // `EVDO_0`, `EVDO_A`, `EVDO_B`, `IS95A` and `IS95B`.
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- case TelephonyManager.NETWORK_TYPE_IDEN:
- return CELL_RADIO_CDMA;
-
- default:
- Log.e(LOG_TAG, "", new IllegalArgumentException("Unexpected network type: " + networkType));
- return String.valueOf(networkType);
- }
- }
-
- @SuppressWarnings("fallthrough")
- private static String getRadioTypeName(int phoneType) {
- switch (phoneType) {
- case TelephonyManager.PHONE_TYPE_CDMA:
- return RADIO_CDMA;
-
- case TelephonyManager.PHONE_TYPE_GSM:
- return RADIO_GSM;
-
- default:
- Log.e(LOG_TAG, "", new IllegalArgumentException("Unexpected phone type: " + phoneType));
- // fallthrough
-
- case TelephonyManager.PHONE_TYPE_NONE:
- case TelephonyManager.PHONE_TYPE_SIP:
- // These devices have no radio.
- return "";
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (!(o instanceof CellInfo)) {
- return false;
- }
- CellInfo ci = (CellInfo) o;
- return mRadio.equals(ci.mRadio)
- && mCellRadio.equals(ci.mCellRadio)
- && mMcc == ci.mMcc
- && mMnc == ci.mMnc
- && mCid == ci.mCid
- && mLac == ci.mLac
- && mSignal == ci.mSignal
- && mAsu == ci.mAsu
- && mTa == ci.mTa
- && mPsc == ci.mPsc;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + mRadio.hashCode();
- result = 31 * result + mCellRadio.hashCode();
- result = 31 * result + mMcc;
- result = 31 * result + mMnc;
- result = 31 * result + mCid;
- result = 31 * result + mLac;
- result = 31 * result + mSignal;
- result = 31 * result + mAsu;
- result = 31 * result + mTa;
- result = 31 * result + mPsc;
- return result;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java
deleted file mode 100644
index 193de9923..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/* 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.scanners.cellscanner;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v4.content.LocalBroadcastManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
-import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
-
-public class CellScanner {
- public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".CellScanner.";
- public static final String ACTION_CELLS_SCANNED = ACTION_BASE + "CELLS_SCANNED";
- public static final String ACTION_CELLS_SCANNED_ARG_CELLS = "cells";
- public static final String ACTION_CELLS_SCANNED_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
-
- private static final String LOG_TAG = AppGlobals.makeLogTag(CellScanner.class.getSimpleName());
- private static final long CELL_MIN_UPDATE_TIME = 1000; // milliseconds
-
- private final Context mContext;
- private Timer mCellScanTimer;
- private final Set<String> mCells = new HashSet<String>();
- private final ReportFlushedReceiver mReportFlushedReceiver = new ReportFlushedReceiver();
- private final AtomicBoolean mReportWasFlushed = new AtomicBoolean();
- private Handler mBroadcastScannedHandler;
- private final CellScannerImpl mCellScannerImplementation;
-
- public ArrayList<CellInfo> sTestingModeCellInfoArray;
-
- public interface CellScannerImpl {
- void start();
- boolean isStarted();
- boolean isSupportedOnThisDevice();
- void stop();
- List<CellInfo> getCellInfo();
- }
-
- public CellScanner(Context context) {
- mContext = context;
- mCellScannerImplementation = new CellScannerImplementation(context);
- }
-
- public void start(final ActiveOrPassiveStumbling stumblingMode) {
- if (!mCellScannerImplementation.isSupportedOnThisDevice()) {
- return;
- }
-
- if (mCellScanTimer != null) {
- return;
- }
-
- LocalBroadcastManager.getInstance(mContext).registerReceiver(mReportFlushedReceiver,
- new IntentFilter(Reporter.ACTION_NEW_BUNDLE));
-
- // This is to ensure the broadcast happens from the same thread the CellScanner start() is on
- mBroadcastScannedHandler = new BroadcastScannedHandler(this);
-
- mCellScannerImplementation.start();
-
- mCellScanTimer = new Timer();
-
- mCellScanTimer.schedule(new TimerTask() {
- int mPassiveScanCount;
- @Override
- public void run() {
- if (!mCellScannerImplementation.isStarted()) {
- return;
- }
-
- if (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING &&
- mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
- {
- mPassiveScanCount = 0;
- stop();
- return;
- }
-
- final long curTime = System.currentTimeMillis();
-
- ArrayList<CellInfo> cells = (sTestingModeCellInfoArray != null)? sTestingModeCellInfoArray :
- new ArrayList<CellInfo>(mCellScannerImplementation.getCellInfo());
-
- if (mReportWasFlushed.getAndSet(false)) {
- clearCells();
- }
-
- if (cells.isEmpty()) {
- return;
- }
-
- for (CellInfo cell : cells) {
- addToCells(cell.getCellIdentity());
- }
-
- Intent intent = new Intent(ACTION_CELLS_SCANNED);
- intent.putParcelableArrayListExtra(ACTION_CELLS_SCANNED_ARG_CELLS, cells);
- intent.putExtra(ACTION_CELLS_SCANNED_ARG_TIME, curTime);
- // send to handler, so broadcast is not from timer thread
- Message message = new Message();
- message.obj = intent;
- mBroadcastScannedHandler.sendMessage(message);
-
- }
- }, 0, CELL_MIN_UPDATE_TIME);
- }
-
- private synchronized void clearCells() {
- mCells.clear();
- }
-
- private synchronized void addToCells(String cell) {
- mCells.add(cell);
- }
-
- public synchronized void stop() {
- mReportWasFlushed.set(false);
- clearCells();
- LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReportFlushedReceiver);
-
- if (mCellScanTimer != null) {
- mCellScanTimer.cancel();
- mCellScanTimer = null;
- }
- mCellScannerImplementation.stop();
- }
-
- public synchronized int getCellInfoCount() {
- return mCells.size();
- }
-
- private class ReportFlushedReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context c, Intent i) {
- mReportWasFlushed.set(true);
- }
- }
-
- // Note: this reimplements org.mozilla.gecko.util.WeakReferenceHandler because it's not available here.
- private static class BroadcastScannedHandler extends Handler {
- private WeakReference<CellScanner> mTarget;
-
- public BroadcastScannedHandler(final CellScanner that) {
- super();
- mTarget = new WeakReference<>(that);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final CellScanner that = mTarget.get();
- if (that == null) {
- return;
- }
-
- final Intent intent = (Intent) msg.obj;
- LocalBroadcastManager.getInstance(that.mContext).sendBroadcastSync(intent);
- }
- };
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerImplementation.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerImplementation.java
deleted file mode 100644
index c6674a3c4..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerImplementation.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/* 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.scanners.cellscanner;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.telephony.CellIdentityCdma;
-import android.telephony.CellIdentityGsm;
-import android.telephony.CellIdentityLte;
-import android.telephony.CellIdentityWcdma;
-import android.telephony.CellInfoCdma;
-import android.telephony.CellInfoGsm;
-import android.telephony.CellInfoLte;
-import android.telephony.CellInfoWcdma;
-import android.telephony.CellLocation;
-import android.telephony.CellSignalStrengthCdma;
-import android.telephony.CellSignalStrengthGsm;
-import android.telephony.CellSignalStrengthLte;
-import android.telephony.CellSignalStrengthWcdma;
-import android.telephony.NeighboringCellInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public class CellScannerImplementation implements CellScanner.CellScannerImpl {
-
- protected static String LOG_TAG = AppGlobals.makeLogTag(CellScannerImplementation.class.getSimpleName());
- protected GetAllCellInfoScannerImpl mGetAllInfoCellScanner;
- protected TelephonyManager mTelephonyManager;
- protected boolean mIsStarted;
- protected int mPhoneType;
- protected final Context mContext;
-
- protected volatile int mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
- protected volatile int mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
-
- private PhoneStateListener mPhoneStateListener;
-
- private static class GetAllCellInfoScannerDummy implements GetAllCellInfoScannerImpl {
- @Override
- public List<CellInfo> getAllCellInfo(TelephonyManager tm) {
- return Collections.emptyList();
- }
- }
-
- interface GetAllCellInfoScannerImpl {
- List<CellInfo> getAllCellInfo(TelephonyManager tm);
- }
-
- public CellScannerImplementation(Context context) {
- mContext = context;
- }
-
- public boolean isSupportedOnThisDevice() {
- TelephonyManager telephonyManager = mTelephonyManager;
- if (telephonyManager == null) {
- telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- }
- return telephonyManager != null &&
- (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA ||
- telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM);
- }
-
- @Override
- public synchronized boolean isStarted() {
- return mIsStarted;
- }
-
- @Override
- public synchronized void start() {
- if (mIsStarted || !isSupportedOnThisDevice()) {
- return;
- }
- mIsStarted = true;
-
- if (mTelephonyManager == null) {
- if (Build.VERSION.SDK_INT >= 18 /*Build.VERSION_CODES.JELLY_BEAN_MR2 */) {
- mGetAllInfoCellScanner = new GetAllCellInfoScannerMr2();
- } else {
- mGetAllInfoCellScanner = new GetAllCellInfoScannerDummy();
- }
-
- mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- }
-
- mPhoneStateListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthsChanged(SignalStrength ss) {
- if (ss.isGsm()) {
- mSignalStrength = ss.getGsmSignalStrength();
- } else {
- mCdmaDbm = ss.getCdmaDbm();
- }
- }
- };
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
- }
-
- @Override
- public synchronized void stop() {
- mIsStarted = false;
- if (mTelephonyManager != null && mPhoneStateListener != null) {
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- }
- mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
- mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
- }
-
- @Override
- public synchronized List<CellInfo> getCellInfo() {
- List<CellInfo> records = new ArrayList<CellInfo>();
-
- List<CellInfo> allCells = mGetAllInfoCellScanner.getAllCellInfo(mTelephonyManager);
- if (allCells.isEmpty()) {
- CellInfo currentCell = getCurrentCellInfo();
- if (currentCell == null) {
- return records;
- }
- records.add(currentCell);
- }else {
- records.addAll(allCells);
- }
-
- // getNeighboringCells() sometimes contains more information than that is already
- // in getAllCellInfo(). Use the results of both of them.
- records.addAll(getNeighboringCells());
- return records;
- }
-
- private String getNetworkOperator() {
- String networkOperator = mTelephonyManager.getNetworkOperator();
- // getNetworkOperator() may be unreliable on CDMA networks
- if (networkOperator == null || networkOperator.length() <= 3) {
- networkOperator = mTelephonyManager.getSimOperator();
- }
- return networkOperator;
- }
-
- protected CellInfo getCurrentCellInfo() {
- final CellLocation currentCell = mTelephonyManager.getCellLocation();
- if (currentCell == null) {
- return null;
- }
-
- try {
- final CellInfo info = new CellInfo(mPhoneType);
- final int signalStrength = mSignalStrength;
- final int cdmaDbm = mCdmaDbm;
- info.setCellLocation(currentCell,
- mTelephonyManager.getNetworkType(),
- getNetworkOperator(),
- signalStrength == CellInfo.UNKNOWN_SIGNAL ? null : signalStrength,
- cdmaDbm == CellInfo.UNKNOWN_SIGNAL ? null : cdmaDbm);
- return info;
- } catch (IllegalArgumentException iae) {
- Log.e(LOG_TAG, "Skip invalid or incomplete CellLocation: " + currentCell, iae);
- }
- return null;
- }
-
- private List<CellInfo> getNeighboringCells() {
- // For max fennec compatibility, avoid VERSION_CODES
- if (Build.VERSION.SDK_INT >= 22 /* Build.VERSION_CODES.LOLLIPOP_MR1 */) {
- return Collections.emptyList();
- }
-
- @SuppressWarnings("deprecation")
- Collection<NeighboringCellInfo> cells = mTelephonyManager.getNeighboringCellInfo();
- if (cells == null || cells.isEmpty()) {
- return Collections.emptyList();
- }
-
- String networkOperator = getNetworkOperator();
- List<CellInfo> records = new ArrayList<CellInfo>(cells.size());
- for (NeighboringCellInfo nci : cells) {
- try {
- final CellInfo record = new CellInfo(mPhoneType);
- record.setNeighboringCellInfo(nci, networkOperator);
- if (record.isCellRadioValid()) {
- records.add(record);
- }
- } catch (IllegalArgumentException iae) {
- Log.e(LOG_TAG, "Skip invalid or incomplete NeighboringCellInfo: " + nci, iae);
- }
- }
- return records;
- }
-
-
- @TargetApi(18)
- protected boolean addWCDMACellToList(List<CellInfo> cells,
- android.telephony.CellInfo observedCell,
- TelephonyManager tm) {
- boolean added = false;
- if (Build.VERSION.SDK_INT >= 18 &&
- observedCell instanceof CellInfoWcdma) {
- CellIdentityWcdma ident = ((CellInfoWcdma) observedCell).getCellIdentity();
- if (ident.getMnc() != Integer.MAX_VALUE && ident.getMcc() != Integer.MAX_VALUE) {
- CellInfo cell = new CellInfo(tm.getPhoneType());
- CellSignalStrengthWcdma strength = ((CellInfoWcdma) observedCell).getCellSignalStrength();
- cell.setWcmdaCellInfo(ident.getMcc(),
- ident.getMnc(),
- ident.getLac(),
- ident.getCid(),
- ident.getPsc(),
- strength.getAsuLevel());
- cells.add(cell);
- added = true;
- }
- }
- return added;
- }
-
- @TargetApi(18)
- protected boolean addCellToList(List<CellInfo> cells,
- android.telephony.CellInfo observedCell,
- TelephonyManager tm) {
- if (tm.getPhoneType() == 0) {
- return false;
- }
-
- boolean added = false;
- if (observedCell instanceof CellInfoGsm) {
- CellIdentityGsm ident = ((CellInfoGsm) observedCell).getCellIdentity();
- if (ident.getMcc() != Integer.MAX_VALUE && ident.getMnc() != Integer.MAX_VALUE) {
- CellSignalStrengthGsm strength = ((CellInfoGsm) observedCell).getCellSignalStrength();
- CellInfo cell = new CellInfo(tm.getPhoneType());
- cell.setGsmCellInfo(ident.getMcc(),
- ident.getMnc(),
- ident.getLac(),
- ident.getCid(),
- strength.getAsuLevel());
- cells.add(cell);
- added = true;
- }
- } else if (observedCell instanceof CellInfoCdma) {
- CellInfo cell = new CellInfo(tm.getPhoneType());
- CellIdentityCdma ident = ((CellInfoCdma) observedCell).getCellIdentity();
- CellSignalStrengthCdma strength = ((CellInfoCdma) observedCell).getCellSignalStrength();
- cell.setCdmaCellInfo(ident.getBasestationId(),
- ident.getNetworkId(),
- ident.getSystemId(),
- strength.getDbm());
- cells.add(cell);
- added = true;
- } else if (observedCell instanceof CellInfoLte) {
- CellIdentityLte ident = ((CellInfoLte) observedCell).getCellIdentity();
- if (ident.getMnc() != Integer.MAX_VALUE && ident.getMcc() != Integer.MAX_VALUE) {
- CellInfo cell = new CellInfo(tm.getPhoneType());
- CellSignalStrengthLte strength = ((CellInfoLte) observedCell).getCellSignalStrength();
- cell.setLteCellInfo(ident.getMcc(),
- ident.getMnc(),
- ident.getCi(),
- ident.getPci(),
- ident.getTac(),
- strength.getAsuLevel(),
- strength.getTimingAdvance());
- cells.add(cell);
- added = true;
- }
- }
-
- if (!added && Build.VERSION.SDK_INT >= 18) {
- added = addWCDMACellToList(cells, observedCell, tm);
- }
-
- return added;
- }
-
- @TargetApi(18)
- private class GetAllCellInfoScannerMr2 implements GetAllCellInfoScannerImpl {
- @Override
- public List<CellInfo> getAllCellInfo(TelephonyManager tm) {
- final List<android.telephony.CellInfo> observed = tm.getAllCellInfo();
- if (observed == null || observed.isEmpty()) {
- return Collections.emptyList();
- }
-
- List<CellInfo> cells = new ArrayList<CellInfo>(observed.size());
- for (android.telephony.CellInfo observedCell : observed) {
- if (!addCellToList(cells, observedCell, tm)) {
- //Log.i(LOG_TAG, "Skipped CellInfo of unknown class: " + observedCell.toString());
- }
- }
- return cells;
- }
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java
deleted file mode 100644
index 308e35678..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/* 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.uploadthread;
-
-import android.os.AsyncTask;
-import android.util.Log;
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.mozilla.mozstumbler.service.Prefs;
-import org.mozilla.mozstumbler.service.utils.AbstractCommunicator;
-import org.mozilla.mozstumbler.service.utils.AbstractCommunicator.SyncSummary;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
-import org.mozilla.mozstumbler.service.utils.NetworkUtils;
-
-/* Only one at a time may be uploading. If executed while another upload is in progress
-* it will return immediately, and SyncResult is null.
-*
-* Threading:
-* Uploads on a separate thread. ONLY DataStorageManager is thread-safe, do not call
-* preferences, do not call any code that isn't thread-safe. You will cause suffering.
-* An exception is made for AppGlobals.isDebug, a false reading is of no consequence. */
-public class AsyncUploader extends AsyncTask<Void, Void, SyncSummary> {
- private static final String LOG_TAG = AppGlobals.makeLogTag(AsyncUploader.class.getSimpleName());
- private final AsyncUploadArgs mUploadArgs;
- private final Object mListenerLock = new Object();
- private AsyncUploaderListener mListener;
- private static final AtomicBoolean sIsUploading = new AtomicBoolean();
- private String mNickname;
-
- public interface AsyncUploaderListener {
- public void onUploadComplete(SyncSummary result);
- public void onUploadProgress();
- }
-
- public static class AsyncUploadArgs {
- public final NetworkUtils mNetworkUtils;
- public final boolean mShouldIgnoreWifiStatus;
- public final boolean mUseWifiOnly;
- public AsyncUploadArgs(NetworkUtils networkUtils,
- boolean shouldIgnoreWifiStatus,
- boolean useWifiOnly) {
- mNetworkUtils = networkUtils;
- mShouldIgnoreWifiStatus = shouldIgnoreWifiStatus;
- mUseWifiOnly = useWifiOnly;
- }
- }
-
- public AsyncUploader(AsyncUploadArgs args, AsyncUploaderListener listener) {
- mListener = listener;
- mUploadArgs = args;
- }
-
- public void setNickname(String name) {
- mNickname = name;
- }
-
- public void clearListener() {
- synchronized (mListenerLock) {
- mListener = null;
- }
- }
-
- public static boolean isUploading() {
- return sIsUploading.get();
- }
-
- @Override
- protected SyncSummary doInBackground(Void... voids) {
- if (sIsUploading.get()) {
- // This if-block is not synchronized, don't care, this is an erroneous usage.
- Log.d(LOG_TAG, "Usage error: check isUploading first, only one at a time task usage is permitted.");
- return null;
- }
-
- sIsUploading.set(true);
- SyncSummary result = new SyncSummary();
- Runnable progressListener = null;
-
- // no need to lock here, lock is checked again later
- if (mListener != null) {
- progressListener = new Runnable() {
- @Override
- public void run() {
- synchronized (mListenerLock) {
- if (mListener != null) {
- mListener.onUploadProgress();
- }
- }
- }
- };
- }
-
- uploadReports(result, progressListener);
-
- return result;
- }
- @Override
- protected void onPostExecute(SyncSummary result) {
- sIsUploading.set(false);
-
- synchronized (mListenerLock) {
- if (mListener != null) {
- mListener.onUploadComplete(result);
- }
- }
- }
- @Override
- protected void onCancelled(SyncSummary result) {
- sIsUploading.set(false);
- }
-
- private class Submitter extends AbstractCommunicator {
- private static final String SUBMIT_URL = "https://location.services.mozilla.com/v1/submit";
-
- @Override
- public String getUrlString() {
- return SUBMIT_URL;
- }
-
- @Override
- public String getNickname(){
- return mNickname;
- }
-
- @Override
- public NetworkSendResult cleanSend(byte[] data) {
- final NetworkSendResult result = new NetworkSendResult();
- try {
- result.bytesSent = this.send(data, ZippedState.eAlreadyZipped);
- result.errorCode = 0;
- } catch (IOException ex) {
- String msg = "Error submitting: " + ex;
- if (ex instanceof HttpErrorException) {
- result.errorCode = ((HttpErrorException) ex).responseCode;
- msg += " Code:" + result.errorCode;
- }
- Log.e(LOG_TAG, msg);
- AppGlobals.guiLogError(msg);
- }
- return result;
- }
- }
-
- private void uploadReports(AbstractCommunicator.SyncSummary syncResult, Runnable progressListener) {
- long uploadedObservations = 0;
- long uploadedCells = 0;
- long uploadedWifis = 0;
-
- if (!mUploadArgs.mShouldIgnoreWifiStatus && mUploadArgs.mUseWifiOnly &&
- !mUploadArgs.mNetworkUtils.isWifiAvailable()) {
- if (AppGlobals.isDebug) {
- Log.d(LOG_TAG, "not on WiFi, not sending");
- }
- syncResult.numIoExceptions += 1;
- return;
- }
-
- Submitter submitter = new Submitter();
- DataStorageManager dm = DataStorageManager.getInstance();
-
- String error = null;
-
- try {
- DataStorageManager.ReportBatch batch = dm.getFirstBatch();
- while (batch != null) {
- AbstractCommunicator.NetworkSendResult result = submitter.cleanSend(batch.data);
-
- if (result.errorCode == 0) {
- syncResult.totalBytesSent += result.bytesSent;
-
- dm.delete(batch.filename);
-
- uploadedObservations += batch.reportCount;
- uploadedWifis += batch.wifiCount;
- uploadedCells += batch.cellCount;
- } else {
- if (result.errorCode / 100 == 4) {
- // delete on 4xx, no point in resending
- dm.delete(batch.filename);
- } else {
- DataStorageManager.getInstance().saveCurrentReportsSendBufferToDisk();
- }
- syncResult.numIoExceptions += 1;
- }
-
- if (progressListener != null) {
- progressListener.run();
- }
-
- batch = dm.getNextBatch();
- }
- }
- catch (IOException ex) {
- error = ex.toString();
- }
-
- try {
- dm.incrementSyncStats(syncResult.totalBytesSent, uploadedObservations, uploadedCells, uploadedWifis);
- } catch (IOException ex) {
- error = ex.toString();
- } finally {
- if (error != null) {
- syncResult.numIoExceptions += 1;
- Log.d(LOG_TAG, error);
- AppGlobals.guiLogError(error + " (uploadReports)");
- }
- submitter.close();
- }
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java
deleted file mode 100644
index d6680a161..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/* 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.uploadthread;
-
-import android.app.AlarmManager;
-import android.app.IntentService;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.Prefs;
-import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
-import org.mozilla.mozstumbler.service.utils.NetworkUtils;
-
-// Only if data is queued and device awake: check network availability and upload.
-// MozStumbler use: this alarm is periodic and repeating.
-// Fennec use: The alarm is single-shot and it is set to run -if there is data in the queue-
-// under these conditions:
-// 1) Fennec start/pause (actually gecko start which is ~4 sec after Fennec start).
-// 2) Changing the pref in Fennec to stumble or not.
-// 3) Boot intent (and SD card app available intent).
-//
-// Threading:
-// - scheduled from the stumbler thread
-// - triggered from the main thread
-// - actual work is done the upload thread (AsyncUploader)
-public class UploadAlarmReceiver extends BroadcastReceiver {
- private static final String LOG_TAG = AppGlobals.makeLogTag(UploadAlarmReceiver.class.getSimpleName());
- private static final String EXTRA_IS_REPEATING = "is_repeating";
- private static boolean sIsAlreadyScheduled;
-
- public UploadAlarmReceiver() {}
-
- public static class UploadAlarmService extends IntentService {
-
- public UploadAlarmService(String name) {
- super(name);
- // makes the service START_NOT_STICKY, that is, the service is not auto-restarted
- setIntentRedelivery(false);
- }
-
- public UploadAlarmService() {
- this(LOG_TAG);
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- if (intent == null) {
- return;
- }
- boolean isRepeating = intent.getBooleanExtra(EXTRA_IS_REPEATING, true);
- if (DataStorageManager.getInstance() == null) {
- DataStorageManager.createGlobalInstance(this, null);
- }
- upload(isRepeating);
- }
-
- void upload(boolean isRepeating) {
- if (!isRepeating) {
- sIsAlreadyScheduled = false;
- }
-
- // Defensive approach: if it is too old, delete all data
- long oldestMs = DataStorageManager.getInstance().getOldestBatchTimeMs();
- int maxWeeks = DataStorageManager.getInstance().getMaxWeeksStored();
- if (oldestMs > 0) {
- long currentTime = System.currentTimeMillis();
- long msPerWeek = 604800 * 1000;
- if (currentTime - oldestMs > maxWeeks * msPerWeek) {
- DataStorageManager.getInstance().deleteAll();
- UploadAlarmReceiver.cancelAlarm(this, isRepeating);
- return;
- }
- }
-
- NetworkUtils networkUtils = new NetworkUtils(this);
- if (networkUtils.isWifiAvailable() &&
- !AsyncUploader.isUploading()) {
- Log.d(LOG_TAG, "Alarm upload(), call AsyncUploader");
- AsyncUploader.AsyncUploadArgs settings =
- new AsyncUploader.AsyncUploadArgs(networkUtils,
- Prefs.getInstance(this).getWifiScanAlways(),
- Prefs.getInstance(this).getUseWifiOnly());
- AsyncUploader uploader = new AsyncUploader(settings, null);
- uploader.setNickname(Prefs.getInstance(this).getNickname());
- uploader.execute();
- // we could listen for completion and cancel, instead, cancel on next alarm when db empty
- }
- }
- }
-
- static PendingIntent createIntent(Context c, boolean isRepeating) {
- Intent intent = new Intent(c, UploadAlarmReceiver.class);
- intent.putExtra(EXTRA_IS_REPEATING, isRepeating);
- PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent, 0);
- return pi;
- }
-
- public static void cancelAlarm(Context c, boolean isRepeating) {
- Log.d(LOG_TAG, "cancelAlarm");
- // this is to stop scheduleAlarm from constantly rescheduling, not to guard cancellation.
- sIsAlreadyScheduled = false;
- AlarmManager alarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
- PendingIntent pi = createIntent(c, isRepeating);
- alarmManager.cancel(pi);
- }
-
- public static void scheduleAlarm(Context c, long secondsToWait, boolean isRepeating) {
- if (sIsAlreadyScheduled) {
- return;
- }
-
- long intervalMsec = secondsToWait * 1000;
- Log.d(LOG_TAG, "schedule alarm (ms):" + intervalMsec);
-
- sIsAlreadyScheduled = true;
- AlarmManager alarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
- PendingIntent pi = createIntent(c, isRepeating);
-
- long triggerAtMs = System.currentTimeMillis() + intervalMsec;
- if (isRepeating) {
- alarmManager.setInexactRepeating(AlarmManager.RTC, triggerAtMs, intervalMsec, pi);
- } else {
- alarmManager.set(AlarmManager.RTC, triggerAtMs, pi);
- }
- }
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- Intent startServiceIntent = new Intent(context, UploadAlarmService.class);
- context.startService(startServiceIntent);
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java
deleted file mode 100644
index 70816371a..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/* 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.utils;
-
-import android.os.Build;
-import android.util.Log;
-
-import org.mozilla.mozstumbler.service.AppGlobals;
-import org.mozilla.mozstumbler.service.Prefs;
-
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-public abstract class AbstractCommunicator {
-
- private static final String LOG_TAG = AppGlobals.makeLogTag(AbstractCommunicator.class.getSimpleName());
- private static final String NICKNAME_HEADER = "X-Nickname";
- private static final String USER_AGENT_HEADER = "User-Agent";
- private HttpURLConnection mHttpURLConnection;
- private final String mUserAgent;
- private static int sBytesSentTotal = 0;
- private static String sMozApiKey;
-
- public abstract String getUrlString();
-
- public static class HttpErrorException extends IOException {
- private static final long serialVersionUID = -5404095858043243126L;
- public final int responseCode;
-
- public HttpErrorException(int responseCode) {
- super();
- this.responseCode = responseCode;
- }
-
- public boolean isTemporary() {
- return responseCode >= 500 && responseCode <= 599;
- }
- }
-
- public static class SyncSummary {
- public int numIoExceptions;
- public int totalBytesSent;
- }
-
- public static class NetworkSendResult {
- public int bytesSent;
- // Zero is no error, for HTTP error cases, set this code to the error
- public int errorCode = -1;
- }
-
- public abstract NetworkSendResult cleanSend(byte[] data);
-
- public String getNickname() {
- return null;
- }
-
- public AbstractCommunicator() {
- Prefs prefs = Prefs.getInstanceWithoutContext();
- mUserAgent = (prefs != null)? prefs.getUserAgent() : "fennec-stumbler-unset-user-agent";
- }
-
- private void openConnectionAndSetHeaders() {
- try {
- Prefs prefs = Prefs.getInstanceWithoutContext();
- if (sMozApiKey == null || prefs != null) {
- sMozApiKey = prefs.getMozApiKey();
- }
- URL url = new URL(getUrlString() + "?key=" + sMozApiKey);
- mHttpURLConnection = (HttpURLConnection) url.openConnection();
- mHttpURLConnection.setRequestMethod("POST");
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException(e);
- } catch (IOException e) {
- Log.e(LOG_TAG, "Couldn't open a connection: " + e);
- }
- mHttpURLConnection.setDoOutput(true);
- mHttpURLConnection.setRequestProperty(USER_AGENT_HEADER, mUserAgent);
- mHttpURLConnection.setRequestProperty("Content-Type", "application/json");
-
- // Workaround for a bug in Android mHttpURLConnection. When the library
- // reuses a stale connection, the connection may fail with an EOFException
- if (Build.VERSION.SDK_INT > 13 && Build.VERSION.SDK_INT < 19) {
- mHttpURLConnection.setRequestProperty("Connection", "Close");
- }
- String nickname = getNickname();
- if (nickname != null) {
- mHttpURLConnection.setRequestProperty(NICKNAME_HEADER, nickname);
- }
- }
-
- private byte[] zipData(byte[] data) throws IOException {
- byte[] output = Zipper.zipData(data);
- return output;
- }
-
- private void sendData(byte[] data) throws IOException{
- mHttpURLConnection.setFixedLengthStreamingMode(data.length);
- OutputStream out = new BufferedOutputStream(mHttpURLConnection.getOutputStream());
- out.write(data);
- out.flush();
- int code = mHttpURLConnection.getResponseCode();
- final boolean isSuccessCode2XX = (code/100 == 2);
- if (!isSuccessCode2XX) {
- throw new HttpErrorException(code);
- }
- }
-
- public enum ZippedState { eNotZipped, eAlreadyZipped };
- /* Return the number of bytes sent. */
- public int send(byte[] data, ZippedState isAlreadyZipped) throws IOException {
- openConnectionAndSetHeaders();
- String logMsg;
- try {
- if (isAlreadyZipped != ZippedState.eAlreadyZipped) {
- data = zipData(data);
- }
- mHttpURLConnection.setRequestProperty("Content-Encoding","gzip");
- } catch (IOException e) {
- Log.e(LOG_TAG, "Couldn't compress and send data, falling back to plain-text: ", e);
- close();
- }
-
- try {
- sendData(data);
- } finally {
- close();
- }
- sBytesSentTotal += data.length;
- logMsg = "Send data: " + String.format("%.2f", data.length / 1024.0) + " kB";
- logMsg += " Session Total:" + String.format("%.2f", sBytesSentTotal / 1024.0) + " kB";
- AppGlobals.guiLogInfo(logMsg, "#FFFFCC", true);
- Log.d(LOG_TAG, logMsg);
- return data.length;
- }
-
- public InputStream getInputStream() {
- try {
- return mHttpURLConnection.getInputStream();
- } catch (IOException e) {
- return mHttpURLConnection.getErrorStream();
- }
- }
-
- public void close() {
- if (mHttpURLConnection == null) {
- return;
- }
- mHttpURLConnection.disconnect();
- mHttpURLConnection = null;
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java
deleted file mode 100644
index b3b33b02a..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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.utils;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-
-public final class NetworkUtils {
- private static final String LOG_TAG = AppGlobals.makeLogTag(NetworkUtils.class.getSimpleName());
-
- ConnectivityManager mConnectivityManager;
-
- public NetworkUtils(Context context) {
- mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- public synchronized boolean isWifiAvailable() {
- if (mConnectivityManager == null) {
- Log.e(LOG_TAG, "ConnectivityManager is null!");
- return false;
- }
-
- NetworkInfo aNet = mConnectivityManager.getActiveNetworkInfo();
- return (aNet != null && aNet.getType() == ConnectivityManager.TYPE_WIFI);
- }
-
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java
deleted file mode 100644
index 8387c7edd..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.mozilla.mozstumbler.service.utils;
-
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * 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.
- */
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-
-/* This code is copied from android IntentService, with stopSelf commented out. */
-public abstract class PersistentIntentService extends Service {
- private volatile Looper mServiceLooper;
- private volatile ServiceHandler mServiceHandler;
- private final String mName;
- private boolean mRedelivery;
-
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- onHandleIntent((Intent) msg.obj);
- // stopSelf(msg.arg1); <-- modified from original file
- }
- }
-
- public PersistentIntentService(String name) {
- super();
- mName = name;
- }
-
- public void setIntentRedelivery(boolean enabled) {
- mRedelivery = enabled;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
- thread.start();
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper);
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- msg.obj = intent;
- mServiceHandler.sendMessage(msg);
- return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
- }
-
- @Override
- public void onDestroy() {
- mServiceLooper.quit();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- protected abstract void onHandleIntent(Intent intent);
-}
-
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/TelemetryWrapper.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/TelemetryWrapper.java
deleted file mode 100644
index 91cde26f2..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/TelemetryWrapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.mozilla.mozstumbler.service.utils;
-
-import android.util.Log;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class TelemetryWrapper {
- private static final String LOG_TAG = AppGlobals.makeLogTag(TelemetryWrapper.class.getSimpleName());
- private static Method mAddToHistogram;
-
- public static void addToHistogram(String key, int value) {
- if (mAddToHistogram == null) {
- try {
- Class<?> telemetry = Class.forName("org.mozilla.gecko.Telemetry");
- mAddToHistogram = telemetry.getMethod("addToHistogram", String.class, int.class);
- } catch (ClassNotFoundException e) {
- Log.d(LOG_TAG, "Class not found!");
- return;
- } catch (NoSuchMethodException e) {
- Log.d(LOG_TAG, "Method not found!");
- return;
- }
- }
-
- if (mAddToHistogram != null) {
- try {
- mAddToHistogram.invoke(null, key, value);
- }
- catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
- Log.d(LOG_TAG, "Got exception invoking.");
- }
- }
- }
-}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java
deleted file mode 100644
index 90e0ee7f5..000000000
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 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.utils;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-public class Zipper {
- public static byte[] zipData(byte[] data) throws IOException {
- final ByteArrayOutputStream os = new ByteArrayOutputStream();
- GZIPOutputStream gstream = new GZIPOutputStream(os);
- byte[] output;
- try {
- gstream.write(data);
- gstream.finish();
- output = os.toByteArray();
- } finally {
- gstream.close();
- os.close();
- }
- return output;
- }
-
- public static String unzipData(byte[] data) throws IOException {
- StringBuilder result = new StringBuilder();
- final ByteArrayInputStream bs = new ByteArrayInputStream(data);
- GZIPInputStream gstream = new GZIPInputStream(bs);
- try {
- InputStreamReader reader = new InputStreamReader(gstream);
- BufferedReader in = new BufferedReader(reader);
- String read;
- while ((read = in.readLine()) != null) {
- result.append(read);
- }
- } finally {
- gstream.close();
- bs.close();
- }
- return result.toString();
- }
-}