org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager.java Source code

Java tutorial

Introduction

Here is the source code for org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager.java

Source

/* 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.location.Location;
import android.support.v4.content.LocalBroadcastManager;

import org.mozilla.mozstumbler.service.AppGlobals;
import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
import org.mozilla.mozstumbler.service.Prefs;
import org.mozilla.mozstumbler.service.core.logging.ClientLog;
import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
import org.mozilla.mozstumbler.service.stumblerthread.motiondetection.LocationChangeSensor;
import org.mozilla.mozstumbler.service.stumblerthread.motiondetection.MotionSensor;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
import org.mozilla.mozstumbler.service.utils.BatteryCheckReceiver;
import org.mozilla.mozstumbler.svclocator.ServiceLocator;
import org.mozilla.mozstumbler.svclocator.services.log.ILogger;
import org.mozilla.mozstumbler.svclocator.services.log.LoggerUtil;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ScanManager {
    public static final String ACTION_SCAN_PAUSED_USER_MOTIONLESS = AppGlobals.ACTION_NAMESPACE
            + ".NOTIFY_USER_MOTIONLESS";
    public static final String ACTION_SCAN_UNPAUSED_USER_MOVED = AppGlobals.ACTION_NAMESPACE + ".NOTIFY_USER_MOVED";

    private ILogger Log = (ILogger) ServiceLocator.getInstance().getService(ILogger.class);
    private static final String LOG_TAG = LoggerUtil.makeLogTag(ScanManager.class);

    private static Context mAppContext;
    private Timer mPassiveModeFlushTimer;

    private GPSScanner mGPSScanner;
    private WifiScanner mWifiScanner;
    private CellScanner mCellScanner;

    private ActiveOrPassiveStumbling mStumblingMode = ActiveOrPassiveStumbling.ACTIVE_STUMBLING;

    private BatteryCheckReceiver mPassiveModeBatteryChecker;
    private PassiveModeBatteryState mPassiveModeBatteryState;
    private BatteryCheckReceiver.BatteryCheckCallback mBatteryCheckCallback = new BatteryCheckReceiver.BatteryCheckCallback() {
        @Override
        public void batteryCheckCallback(BatteryCheckReceiver receiver) {
            if (mPassiveModeBatteryState == PassiveModeBatteryState.IGNORE_BATTERY_STATE) {
                return;
            }
            final int kMinBatteryPct = 15;
            boolean isLow = receiver.isBatteryNotChargingAndLessThan(kMinBatteryPct);
            mPassiveModeBatteryState = isLow ? PassiveModeBatteryState.LOW : PassiveModeBatteryState.OK;
        }
    };
    private LocationChangeSensor mLocationChangeSensor;
    private MotionSensor mMotionSensor;

    enum ScannerState {
        STOPPED, STARTED, STARTED_BUT_PAUSED_MOTIONLESS
    }

    ScannerState mScannerState = ScannerState.STOPPED;

    // After DetectUnchangingLocation reports the user is not moving, and the scanning pauses,
    // then use MotionSensor to determine when to wake up and start scanning again.
    private final BroadcastReceiver mDetectUserIdleReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (isStopped() || !Prefs.getInstance(mAppContext).isMotionSensorEnabled()) {
                return;
            }
            pauseScanning();

            if (AppGlobals.isDebug) {
                ClientLog.d(LOG_TAG, "MotionSensor started");
            }
            mMotionSensor.start();

            Intent sendIntent = new Intent(ACTION_SCAN_PAUSED_USER_MOTIONLESS);
            LocalBroadcastManager.getInstance(mAppContext).sendBroadcastSync(sendIntent);
        }
    };

    private final BroadcastReceiver mDetectMotionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (mScannerState != ScannerState.STARTED_BUT_PAUSED_MOTIONLESS) {
                return;
            }
            mScannerState = ScannerState.STOPPED; // To ensure startScanning() runs
            startScanning();
            mMotionSensor.stop();

            Intent sendIntent = new Intent(ACTION_SCAN_UNPAUSED_USER_MOVED);
            LocalBroadcastManager.getInstance(mAppContext).sendBroadcastSync(sendIntent);
        }
    };

    public ScanManager() {
    }

    public void initContext(Context appCtx) {
        mAppContext = appCtx;
    }

    // By default, if the battery level is low, then the service stops scanning, however the client
    // can disable this and perform more complex logic
    public void setShouldStopPassiveScanningOnBatteryLow(boolean shouldStop) {
        mPassiveModeBatteryState = shouldStop ? PassiveModeBatteryState.OK
                : PassiveModeBatteryState.IGNORE_BATTERY_STATE;
    }

    public void newPassiveGpsLocation() {
        if (mPassiveModeBatteryState == PassiveModeBatteryState.LOW) {
            return;
        }

        if (AppGlobals.isDebug) {
            ClientLog.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);
                if (mAppContext == null) {
                    return;
                }
                LocalBroadcastManager.getInstance(mAppContext).sendBroadcastSync(flush);
            }
        }, when);
    }

    public synchronized boolean isPassiveMode() {
        return ActiveOrPassiveStumbling.PASSIVE_STUMBLING == mStumblingMode;
    }

    public synchronized void setPassiveMode(boolean on) {
        if (on && mPassiveModeBatteryChecker == null) {
            mPassiveModeBatteryChecker = new BatteryCheckReceiver(mAppContext, mBatteryCheckCallback);
        }
        mStumblingMode = (on) ? ActiveOrPassiveStumbling.PASSIVE_STUMBLING
                : ActiveOrPassiveStumbling.ACTIVE_STUMBLING;
    }

    private synchronized boolean pauseScanning() {
        if (isStopped()) {
            return false;
        }
        mScannerState = ScannerState.STARTED_BUT_PAUSED_MOTIONLESS;
        return stopAllScanners();
    }

    public synchronized void startScanning() {
        ClientLog.d(LOG_TAG, "ScanManager::startScanning");

        if (!isStopped()) {
            return;
        }

        mScannerState = ScannerState.STARTED;

        if (mLocationChangeSensor == null) {
            mLocationChangeSensor = new LocationChangeSensor(mAppContext, mDetectUserIdleReceiver);
        }
        mLocationChangeSensor.start();

        if (mMotionSensor == null) {
            LocalBroadcastManager.getInstance(mAppContext).registerReceiver(mDetectMotionReceiver,
                    new IntentFilter(MotionSensor.ACTION_USER_MOTION_DETECTED));

            mMotionSensor = new MotionSensor(mAppContext);
        }

        if (AppGlobals.isDebug) {
            // Simulation contexts are only allowed for debug builds.
            Prefs prefs = Prefs.getInstanceWithoutContext();
            if (prefs != null) {
                if (prefs.isSimulateStumble()) {
                    ISimulatorService simSvc = (ISimulatorService) ServiceLocator.getInstance()
                            .getService(ISimulatorService.class);
                    simSvc.startSimulation(mAppContext);

                    ClientLog.d(LOG_TAG, "ScanManager using SimulateStumbleContextWrapper");
                }
            }
        }

        mGPSScanner = new GPSScanner(mAppContext, this);
        mWifiScanner = new WifiScanner(mAppContext);
        mCellScanner = new CellScanner(mAppContext);

        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
        } else {
            Log.d(LOG_TAG, "Wifi and Cell Scanners are not engaged with passive mode.");
        }
    }

    public synchronized boolean stopScanning() {
        if (isStopped()) {
            return false;
        }
        mScannerState = ScannerState.STOPPED;
        mMotionSensor.scannerFullyStopped();
        return stopAllScanners();
    }

    private boolean stopAllScanners() {
        ISimulatorService sim = (ISimulatorService) ServiceLocator.getInstance()
                .getService(ISimulatorService.class);
        sim.stopSimulation(); // this is always safe as it's a lazy dynamic proxy

        if (AppGlobals.isDebug) {
            ClientLog.d(LOG_TAG, "Scanning stopped");
        }

        mLocationChangeSensor.stop();
        mMotionSensor.stop();

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

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

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

        return true;
    }

    public synchronized boolean isStopped() {
        return mScannerState == ScannerState.STOPPED;
    }

    public int getVisibleAPCount() {
        return (mWifiScanner == null) ? 0 : mWifiScanner.getVisibleAPCount();
    }

    public int getWifiStatus() {
        return (mWifiScanner == null) ? 0 : mWifiScanner.getStatus();
    }

    public int getVisibleCellInfoCount() {
        return (mCellScanner == null) ? 0 : mCellScanner.getVisibleCellInfoCount();
    }

    public int getLocationCount() {
        return (mGPSScanner == null) ? 0 : mGPSScanner.getLocationCount();
    }

    public Location getLocation() {
        return (mGPSScanner == null) ? new Location("null") : mGPSScanner.getLocation();
    }

    private enum PassiveModeBatteryState {
        OK, LOW, IGNORE_BATTERY_STATE
    }
}