aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java7
-rw-r--r--main/src/cgeo/geocaching/sensors/DirectionProvider.java91
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoDataProvider.java12
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoDirHandler.java4
-rw-r--r--main/src/cgeo/geocaching/utils/StartableHandlerThread.java80
5 files changed, 145 insertions, 49 deletions
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index ef224ff..21307d2 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -39,12 +39,15 @@ public class CgeoApplication extends Application {
public synchronized Observable<ImmutablePair<IGeoData, Float>> geoDirObservable() {
if (geoDir == null) {
- geoDir = Observable.combineLatest(GeoDataProvider.create(this), DirectionProvider.create(this), new Func2<IGeoData, Float, ImmutablePair<IGeoData, Float>>() {
+ final Observable<IGeoData> geo = GeoDataProvider.create(this);
+ final Observable<Float> dir = DirectionProvider.create(this);
+ final Observable<ImmutablePair<IGeoData, Float>> combined = Observable.combineLatest(geo, dir, new Func2<IGeoData, Float, ImmutablePair<IGeoData, Float>>() {
@Override
public ImmutablePair<IGeoData, Float> call(final IGeoData geoData, final Float dir) {
- return new ImmutablePair<IGeoData, Float>(geoData, dir);
+ return ImmutablePair.of(geoData, dir);
}
});
+ geoDir = combined.publish().refCount();
}
return geoDir;
}
diff --git a/main/src/cgeo/geocaching/sensors/DirectionProvider.java b/main/src/cgeo/geocaching/sensors/DirectionProvider.java
index 162f14c..8efbc1f 100644
--- a/main/src/cgeo/geocaching/sensors/DirectionProvider.java
+++ b/main/src/cgeo/geocaching/sensors/DirectionProvider.java
@@ -1,15 +1,13 @@
package cgeo.geocaching.sensors;
+import android.os.Process;
import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.utils.StartableHandlerThread;
import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
-import rx.Subscription;
-import rx.observables.ConnectableObservable;
import rx.subjects.BehaviorSubject;
-import rx.subscriptions.Subscriptions;
-import rx.functions.Action0;
import android.app.Activity;
import android.content.Context;
@@ -17,39 +15,24 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.*;
-public class DirectionProvider implements OnSubscribe<Float> {
+public class DirectionProvider {
- private final SensorManager sensorManager;
- private final BehaviorSubject<Float> subject = BehaviorSubject.create(0.0f);
+ private static final BehaviorSubject<Float> subject = BehaviorSubject.create(0.0f);
- static public Observable<Float> create(final Context context) {
- return new DirectionProvider((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).worker.refCount();
- }
+ static class Listener implements SensorEventListener, StartableHandlerThread.Callback {
- private DirectionProvider(final SensorManager sensorManager) {
- this.sensorManager = sensorManager;
- }
+ private int count = 0;
+ private SensorManager sensorManager;
- @Override
- public void call(final Subscriber<? super Float> subscriber) {
- subject.distinctUntilChanged().subscribe(subscriber);
- }
+ @Override
+ public void onSensorChanged(final SensorEvent event) {
+ subject.onNext(event.values[0]);
+ }
- private final ConnectableObservable<Float> worker = new ConnectableObservable<Float>(this) {
@Override
- public Subscription connect() {
- @SuppressWarnings("deprecation")
- // This will be removed when using a new location service. Until then, it is okay to be used.
- final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- final SensorEventListener listener = new SensorEventListener() {
- @Override
- public void onSensorChanged(final SensorEvent event) {
- subject.onNext(event.values[0]);
- }
-
- @Override
- public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
+ public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
/*
* There is a bug in Android, which apparently causes this method to be called every
* time the sensor _value_ changed, even if the _accuracy_ did not change. So logging
@@ -60,19 +43,43 @@ public class DirectionProvider implements OnSubscribe<Float> {
* See for example https://code.google.com/p/android/issues/detail?id=14792
*/
- //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
- }
- };
-
- sensorManager.registerListener(listener, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
- return Subscriptions.create(new Action0() {
- @Override
- public void call() {
- sensorManager.unregisterListener(listener);
- }
- });
+ //Log.i(Settings.tag, "Compass' accuracy is low (" + accuracy + ")");
}
- };
+
+ // This will be removed when using a new location service. Until then, it is okay to be used.
+ @SuppressWarnings("deprecation")
+ @Override
+ public void start(final Context context, final Handler handler) {
+ if (++count == 1) {
+ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL, handler);
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (--count == 0) {
+ sensorManager.unregisterListener(this);
+ }
+ }
+
+ }
+
+ private static final StartableHandlerThread handlerThread =
+ new StartableHandlerThread("DirectionProvider thread", Process.THREAD_PRIORITY_BACKGROUND, new Listener());
+ static {
+ handlerThread.start();
+ }
+
+ static public Observable<Float> create(final Context context) {
+ return Observable.create(new OnSubscribe<Float>() {
+ @Override
+ public void call(final Subscriber<? super Float> subscriber) {
+ handlerThread.start(subscriber, context);
+ subject.subscribe(subscriber);
+ }
+ });
+ }
/**
* Take the phone rotation (through a given activity) in account and adjust the direction.
diff --git a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
index 160d98d..a77b477 100644
--- a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
+++ b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
@@ -1,7 +1,9 @@
package cgeo.geocaching.sensors;
+import android.os.*;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.StartableHandlerThread;
import org.apache.commons.lang3.StringUtils;
import rx.Observable;
import rx.Observable.OnSubscribe;
@@ -22,7 +24,6 @@ import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
-import android.os.Bundle;
import java.util.concurrent.TimeUnit;
@@ -33,6 +34,11 @@ public class GeoDataProvider implements OnSubscribe<IGeoData> {
private final LocationData gpsLocation = new LocationData();
private final LocationData netLocation = new LocationData();
private final BehaviorSubject<IGeoData> subject;
+ private static final StartableHandlerThread handlerThread =
+ new StartableHandlerThread("GeoDataProvider thread", android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ static {
+ handlerThread.start();
+ }
public boolean gpsEnabled = false;
public int satellitesVisible = 0;
@@ -92,7 +98,7 @@ public class GeoDataProvider implements OnSubscribe<IGeoData> {
@Override
public Subscription connect() {
final CompositeSubscription subscription = new CompositeSubscription();
- AndroidSchedulers.mainThread().schedule(new Action1<Inner>() {
+ AndroidSchedulers.handlerThread(handlerThread.getHandler()).schedule(new Action1<Inner>() {
@Override
public void call(final Inner inner) {
synchronized(lock) {
@@ -112,7 +118,7 @@ public class GeoDataProvider implements OnSubscribe<IGeoData> {
subscription.add(Subscriptions.create(new Action0() {
@Override
public void call() {
- AndroidSchedulers.mainThread().schedule(new Action1<Inner>() {
+ AndroidSchedulers.handlerThread(handlerThread.getHandler()).schedule(new Action1<Inner>() {
@Override
public void call(final Inner inner) {
synchronized (lock) {
diff --git a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
index 0af2cc8..588bd84 100644
--- a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
+++ b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
@@ -42,12 +42,12 @@ public abstract class GeoDirHandler {
* preferences allow it).
*/
public Subscription start() {
- return app.geoDirObservable().subscribe(new Action1<ImmutablePair<IGeoData, Float>>() {
+ return app.geoDirObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<ImmutablePair<IGeoData, Float>>() {
@Override
public void call(final ImmutablePair<IGeoData, Float> geoDir) {
handleGeoDir(geoDir);
}
- }, AndroidSchedulers.mainThread());
+ });
}
}
diff --git a/main/src/cgeo/geocaching/utils/StartableHandlerThread.java b/main/src/cgeo/geocaching/utils/StartableHandlerThread.java
new file mode 100644
index 0000000..152badc
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/StartableHandlerThread.java
@@ -0,0 +1,80 @@
+package cgeo.geocaching.utils;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import org.eclipse.jdt.annotation.NonNull;
+import rx.Subscriber;
+import rx.functions.Action0;
+import rx.subscriptions.Subscriptions;
+
+/**
+ * Derivated class of {@link android.os.HandlerThread} with an exposed handler and a start/stop mechanism
+ * based on subscriptions.
+ */
+
+public class StartableHandlerThread extends HandlerThread {
+
+ private final static int START = 1;
+ private final static int STOP = 2;
+
+ static public interface Callback {
+ public void start(final Context context, final Handler handler);
+ public void stop();
+ }
+
+ private class StartableHandler extends Handler {
+ public StartableHandler() {
+ super(StartableHandlerThread.this.getLooper());
+ }
+
+ @Override
+ public void handleMessage(final Message message) {
+ if (callback != null) {
+ switch (message.what) {
+ case START:
+ callback.start((Context) message.obj, this);
+ break;
+ case STOP:
+ callback.stop();
+ break;
+ }
+ }
+ }
+ }
+
+ private Handler handler;
+ private Callback callback;
+
+ public StartableHandlerThread(@NonNull final String name, final int priority, final Callback callback) {
+ super(name, priority);
+ this.callback = callback;
+ }
+
+ public StartableHandlerThread(@NonNull final String name, final int priority) {
+ this(name, priority, null);
+ }
+
+ public Handler getHandler() {
+ if (handler == null) {
+ synchronized(this) {
+ if (handler == null) {
+ handler = new StartableHandler();
+ }
+ }
+ }
+ return handler;
+ }
+
+ public void start(final Subscriber<?> subscriber, final Context context) {
+ getHandler().obtainMessage(START, context).sendToTarget();
+ subscriber.add(Subscriptions.create(new Action0() {
+ @Override
+ public void call() {
+ getHandler().sendEmptyMessage(STOP);
+ }
+ }));
+ }
+
+}