org.mozilla.mozstumbler.client.ObservedLocationsReceiver.java Source code

Java tutorial

Introduction

Here is the source code for org.mozilla.mozstumbler.client.ObservedLocationsReceiver.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.client;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;

import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.mozstumbler.client.mapview.MapFragment;
import org.mozilla.mozstumbler.client.mapview.ObservationPoint;
import org.mozilla.mozstumbler.service.core.logging.Log;
import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
import org.mozilla.mozstumbler.service.stumblerthread.datahandling.StumblerBundle;
import org.mozilla.osmdroid.util.GeoPoint;

import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedList;

public class ObservedLocationsReceiver extends BroadcastReceiver {

    public interface ICountObserver {
        public void observedLocationCountIncrement();
    }

    private static final String LOG_TAG = ObservedLocationsReceiver.class.getSimpleName();
    private WeakReference<MapFragment> mMapActivity = new WeakReference<MapFragment>(null);
    private final LinkedList<ObservationPoint> mCollectionPoints = new LinkedList<ObservationPoint>();
    private final LinkedList<ObservationPoint> mQueuedForMLS = new LinkedList<ObservationPoint>();
    private final int MAX_QUEUED_MLS_POINTS_TO_FETCH = 10;
    private final long FREQ_FETCH_MLS_MS = 5 * 1000;
    private WeakReference<ICountObserver> mCountObserver = new WeakReference<ICountObserver>(null);
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    // Upper bound on the size of the linked lists of points, for memory and performance safety.
    // On older devices, store fewer observations
    private final int MAX_SIZE_OF_POINT_LISTS = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            ? 5000
            : 2500;

    private ObservedLocationsReceiver() {
        mHandler.postDelayed(mFetchMLSRunnable, FREQ_FETCH_MLS_MS);
    }

    private static ObservedLocationsReceiver sInstance;

    public static void createGlobalInstance(Context context, ICountObserver countObserver) {
        sInstance = new ObservedLocationsReceiver();
        sInstance.mCountObserver = new WeakReference<ICountObserver>(countObserver);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Reporter.ACTION_NEW_BUNDLE);
        LocalBroadcastManager.getInstance(context).registerReceiver(sInstance, intentFilter);
    }

    public static ObservedLocationsReceiver getInstance() {
        return sInstance;
    }

    public LinkedList<ObservationPoint> getObservationPoints() {
        return mCollectionPoints;
    }

    private final Runnable mFetchMLSRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (ObservedLocationsReceiver.this) {
                mHandler.postDelayed(mFetchMLSRunnable, FREQ_FETCH_MLS_MS);
                if (mQueuedForMLS.size() < 1 || !ClientPrefs.getInstance().getOnMapShowMLS()) {
                    return;
                }
                int count = 0;
                Iterator<ObservationPoint> li = mQueuedForMLS.iterator();
                while (li.hasNext() && count < MAX_QUEUED_MLS_POINTS_TO_FETCH) {
                    ObservationPoint obs = li.next();
                    if (obs.needsToFetchMLS()) {
                        obs.fetchMLS();
                        count++;
                    } else {
                        if (getMapActivity() != null && obs.pointMLS != null) {
                            getMapActivity().newMLSPoint(obs);
                        }
                        li.remove();
                    }
                }
            }
        }
    };

    // Must be called by map activity when it is showing to get points displayed
    public synchronized void setMapActivity(MapFragment m) {
        mMapActivity = new WeakReference<MapFragment>(m);
    }

    // Must call when map activity stopped, to clear the reference to the map activity object
    public void removeMapActivity() {
        setMapActivity(null);
    }

    private synchronized MapFragment getMapActivity() {
        return mMapActivity.get();
    }

    @Override
    public synchronized void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (!action.equals(Reporter.ACTION_NEW_BUNDLE)) {
            return;
        }

        final StumblerBundle bundle = intent.getParcelableExtra(Reporter.NEW_BUNDLE_ARG_BUNDLE);
        if (bundle == null) {
            return;
        }

        Location position = bundle.getGpsPosition();
        if (position == null) {
            return;
        }
        ObservationPoint observation = new ObservationPoint(new GeoPoint(position));

        try {
            JSONObject jsonBundle = bundle.toMLSJSON();
            observation.setCounts(jsonBundle);

            boolean getInfoForMLS = ClientPrefs.getInstance().isOptionEnabledToShowMLSOnMap();
            if (getInfoForMLS) {
                observation.setMLSQuery(jsonBundle);

                if (mQueuedForMLS.size() < MAX_SIZE_OF_POINT_LISTS) {
                    mQueuedForMLS.addFirst(observation);
                }
            }
        } catch (JSONException e) {
            Log.w(LOG_TAG, "Failed to convert bundle to JSON: " + e);
        }

        // Notify main app of observation
        if (mCountObserver.get() != null) {
            mCountObserver.get().observedLocationCountIncrement();
        }

        while (mCollectionPoints.size() > MAX_SIZE_OF_POINT_LISTS) {
            mCollectionPoints.removeFirst();
        }

        if (mCollectionPoints.size() > 0) {
            observation.mHeading = observation.pointGPS.bearingTo(mCollectionPoints.getLast().pointGPS);
        }
        mCollectionPoints.addLast(observation);

        if (getMapActivity() == null) {
            return;
        }

        getMapActivity().getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                addObservationPointToMap();
            }
        });
    }

    private synchronized void addObservationPointToMap() {
        if (getMapActivity() == null) {
            return;
        }

        getMapActivity().newObservationPoint(mCollectionPoints.getLast());
    }
}