From 855ea472d34b481a7663a34025027fc93f4487d1 Mon Sep 17 00:00:00 2001 From: mar-v-in Date: Wed, 5 Mar 2014 21:31:46 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 + Android.mk | 34 +++++ AndroidManifest.xml | 74 ++++++++++ README.md | 6 + api/Android.mk | 9 ++ api/AndroidManifest.xml | 4 + .../org/microg/nlp/api/LocationBackend.aidl | 10 ++ .../nlp/api/LocationBackendService.java | 71 ++++++++++ .../org/microg/nlp/api/LocationCallback.aidl | 7 + .../org/microg/nlp/api/NlpApiConstants.java | 5 + res/drawable-hdpi/nlp_app_icon.png | Bin 0 -> 3422 bytes res/drawable-mdpi/nlp_app_icon.png | Bin 0 -> 2024 bytes res/drawable-xhdpi/nlp_app_icon.png | Bin 0 -> 5424 bytes res/values/strings.xml | 4 + sample/AndroidManifest.xml | 17 +++ sample/res/drawable/icon.png | Bin 0 -> 990 bytes sample/res/values/strings.xml | 4 + .../nlp/api/sample/SampleBackendService.java | 19 +++ src/org/microg/nlp/Provider.java | 7 + src/org/microg/nlp/ProviderService.java | 53 +++++++ .../microg/nlp/geocode/GeocodeProvider.java | 6 + .../microg/nlp/geocode/GeocodeProviderV1.java | 22 +++ .../microg/nlp/geocode/GeocodeService.java | 17 +++ .../microg/nlp/geocode/GeocodeServiceV1.java | 16 +++ .../microg/nlp/location/BackendHelper.java | 132 ++++++++++++++++++ .../microg/nlp/location/LocationProvider.java | 12 ++ .../nlp/location/LocationProviderV2.java | 79 +++++++++++ .../microg/nlp/location/LocationService.java | 41 ++++++ .../nlp/location/LocationServiceV2.java | 14 ++ src/org/microg/nlp/location/ThreadHelper.java | 56 ++++++++ .../microg/nlp/ui/LocationBackendConfig.java | 91 ++++++++++++ 31 files changed, 813 insertions(+) create mode 100644 .gitignore create mode 100644 Android.mk create mode 100644 AndroidManifest.xml create mode 100644 README.md create mode 100644 api/Android.mk create mode 100644 api/AndroidManifest.xml create mode 100644 api/src/org/microg/nlp/api/LocationBackend.aidl create mode 100644 api/src/org/microg/nlp/api/LocationBackendService.java create mode 100644 api/src/org/microg/nlp/api/LocationCallback.aidl create mode 100644 api/src/org/microg/nlp/api/NlpApiConstants.java create mode 100644 res/drawable-hdpi/nlp_app_icon.png create mode 100644 res/drawable-mdpi/nlp_app_icon.png create mode 100644 res/drawable-xhdpi/nlp_app_icon.png create mode 100644 res/values/strings.xml create mode 100644 sample/AndroidManifest.xml create mode 100644 sample/res/drawable/icon.png create mode 100644 sample/res/values/strings.xml create mode 100644 sample/src/org/microg/nlp/api/sample/SampleBackendService.java create mode 100644 src/org/microg/nlp/Provider.java create mode 100644 src/org/microg/nlp/ProviderService.java create mode 100644 src/org/microg/nlp/geocode/GeocodeProvider.java create mode 100644 src/org/microg/nlp/geocode/GeocodeProviderV1.java create mode 100644 src/org/microg/nlp/geocode/GeocodeService.java create mode 100644 src/org/microg/nlp/geocode/GeocodeServiceV1.java create mode 100644 src/org/microg/nlp/location/BackendHelper.java create mode 100644 src/org/microg/nlp/location/LocationProvider.java create mode 100644 src/org/microg/nlp/location/LocationProviderV2.java create mode 100644 src/org/microg/nlp/location/LocationService.java create mode 100644 src/org/microg/nlp/location/LocationServiceV2.java create mode 100644 src/org/microg/nlp/location/ThreadHelper.java create mode 100644 src/org/microg/nlp/ui/LocationBackendConfig.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4601963 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.iml +gen +bin diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..26f4d3c --- /dev/null +++ b/Android.mk @@ -0,0 +1,34 @@ +# Copyright (c) 2014 μg 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES += $(call all-java-files-under, api/src) + +# For some reason framework has to be added here else GeocoderParams is not found, +# this way everything else is duplicated, but atleast compiles... +LOCAL_JAVA_LIBRARIES := framework com.android.location.provider + +LOCAL_STATIC_JAVA_LIBRARIES := UnifiedNlpApi +LOCAL_PACKAGE_NAME := UnifiedNlp +LOCAL_SDK_VERSION := current +LOCAL_PRIVILEGED_MODULE := true + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..80feb86 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..0941a94 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +The next generation NetworkLocationProvider, based on plugins + +`api` contains files needed to build your custom plugin. +`sample` contains a sample plugin. + +To be build with Android Build System using `make UnifiedNlp` diff --git a/api/Android.mk b/api/Android.mk new file mode 100644 index 0000000..b1a427c --- /dev/null +++ b/api/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := UnifiedNlpApi +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES += src/org/microg/nlp/api/LocationBackend.aidl \ + src/org/microg/nlp/api/LocationCallback.aidl + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/api/AndroidManifest.xml b/api/AndroidManifest.xml new file mode 100644 index 0000000..9adedee --- /dev/null +++ b/api/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/api/src/org/microg/nlp/api/LocationBackend.aidl b/api/src/org/microg/nlp/api/LocationBackend.aidl new file mode 100644 index 0000000..a91e0ab --- /dev/null +++ b/api/src/org/microg/nlp/api/LocationBackend.aidl @@ -0,0 +1,10 @@ +package org.microg.nlp.api; + +import org.microg.nlp.api.LocationCallback; +import android.location.Location; + +interface LocationBackend { + void open(LocationCallback callback); + Location update(); + void close(); +} diff --git a/api/src/org/microg/nlp/api/LocationBackendService.java b/api/src/org/microg/nlp/api/LocationBackendService.java new file mode 100644 index 0000000..0fcd7af --- /dev/null +++ b/api/src/org/microg/nlp/api/LocationBackendService.java @@ -0,0 +1,71 @@ +package org.microg.nlp.api; + +import android.app.Service; +import android.content.Intent; +import android.location.Location; +import android.os.IBinder; +import android.os.RemoteException; + +public abstract class LocationBackendService extends Service { + + private Backend backend = new Backend(); + private LocationCallback callback; + private Location waiting; + + /** + * This method is called, whenever an app requires a location update. This can be a single or a repeated request. + *

+ * You may return null if your backend has no newer location available then the last one. + * Do not send the same {@link android.location.Location} twice, if it's not based on updated/refreshed data. + *

+ * You can completely ignore this method (means returning null) if you use {@link #report(android.location.Location)}. + * + * @return a new {@link android.location.Location} instance or null if not available. + */ + protected abstract Location update(); + + /** + * Directly report a {@link android.location.Location} to the requesting apps. Use this if your updates are based + * on environment changes (eg. cell id change). + * + * @param location the new {@link android.location.Location} instance to be send + */ + public void report(Location location) { + if (callback != null) { + try { + callback.report(location); + } catch (RemoteException e) { + waiting = location; + } + } else { + waiting = location; + } + } + + @Override + public IBinder onBind(Intent intent) { + return backend; + } + + + private class Backend extends LocationBackend.Stub { + @Override + public void open(LocationCallback callback) throws RemoteException { + LocationBackendService.this.callback = callback; + if (waiting != null) { + callback.report(waiting); + waiting = null; + } + } + + @Override + public Location update() throws RemoteException { + return LocationBackendService.this.update(); + } + + @Override + public void close() throws RemoteException { + callback = null; + } + } +} diff --git a/api/src/org/microg/nlp/api/LocationCallback.aidl b/api/src/org/microg/nlp/api/LocationCallback.aidl new file mode 100644 index 0000000..9305acd --- /dev/null +++ b/api/src/org/microg/nlp/api/LocationCallback.aidl @@ -0,0 +1,7 @@ +package org.microg.nlp.api; + +import android.location.Location; + +interface LocationCallback { + void report(in Location location); +} diff --git a/api/src/org/microg/nlp/api/NlpApiConstants.java b/api/src/org/microg/nlp/api/NlpApiConstants.java new file mode 100644 index 0000000..1db32b5 --- /dev/null +++ b/api/src/org/microg/nlp/api/NlpApiConstants.java @@ -0,0 +1,5 @@ +package org.microg.nlp.api; + +public class NlpApiConstants { + public static final String ACTION_LOCATION_BACKEND = "org.microg.nlp.LOCATION_BACKEND"; +} diff --git a/res/drawable-hdpi/nlp_app_icon.png b/res/drawable-hdpi/nlp_app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1654d9c760b8acce0d72c1909318808838df1de7 GIT binary patch literal 3422 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 A$p8QV literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/nlp_app_icon.png b/res/drawable-mdpi/nlp_app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2c1b3c53600dd0fee71431288fa46a8920a00af0 GIT binary patch literal 2024 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 a_WExX*yE7Ob#pEN0000 + + NLP Controller + \ No newline at end of file diff --git a/sample/AndroidManifest.xml b/sample/AndroidManifest.xml new file mode 100644 index 0000000..6b34e2f --- /dev/null +++ b/sample/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/sample/res/drawable/icon.png b/sample/res/drawable/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..08ee50da978889f67f56dced4e8d7c0478d400ea GIT binary patch literal 990 zcmV<410np0P)Bm=9B+4V(stve@Q6Z~?UBYzla^-QYD? z0Gd3uH3KXI6LY!-c(l*pFpq-kpg))cW`oH*q=$ilAOe1XFW?<`0d9jEAjxeU2XFmw zG$MNpdRPQ|EykmOI#dNpGOV9uA!@)_(BZ|ITrPrS#k^_{D*qo&)Mm}x?&p=#t0VaX_V7w2)js(p-os<+{IL81LJ_c?yl`er%DhhA{j4(;R z21c{f7ag=i3*R_y>%2*R1;-gm2~Y=?O7b>-aP5@ewpMox4ZReVl zNd?TmHV?G2&#l}CR|3>p70gul1Fd48E7@oIdD-e|QD76@6`IWVdW8i@ zn5;=rPIol|%xspz0%Yv7l>jkGda1$!6id>J{CWyR`}$MB&SGH~KxhH909pVofEGXt zpaswZXaTeUeNTX-B>kJh{rN6Q?{p);JxTfY%(4vD6wZey^YFRY$jW$6au+P1HcqFS}_r1U^VZ8}TJFh*8Ev9t7!0}gR zULB|5^*rp4!LtGS->HHCbcnGdAOV_G5P%jNI>wgkiw6{s>`)~VYyfM7aYWW{qhqyn zQjGTc+f)jL&j{oEFP;58U{iKAmrJM4!BnGigTNB-Qojpm0ki;G04;zPKntLx09`iu zKP3T9rgfAR;HE|1FJZphMDOxRn^*I^5rE#w&q?z3gHI;u)cNg_I&|}_G2hkz3U_H+ ztz8(KCa;8Xoi<@n=LlFOjQc^qStz=EwOE+n8}MuqeS19Q_E&%b0N#qh)WR6{{{R30 M07*qoM6N<$f=l7H!2kdN literal 0 HcmV?d00001 diff --git a/sample/res/values/strings.xml b/sample/res/values/strings.xml new file mode 100644 index 0000000..9a4ab78 --- /dev/null +++ b/sample/res/values/strings.xml @@ -0,0 +1,4 @@ + + + NetworkLocationV2-SamplePlugin + \ No newline at end of file diff --git a/sample/src/org/microg/nlp/api/sample/SampleBackendService.java b/sample/src/org/microg/nlp/api/sample/SampleBackendService.java new file mode 100644 index 0000000..8432900 --- /dev/null +++ b/sample/src/org/microg/nlp/api/sample/SampleBackendService.java @@ -0,0 +1,19 @@ +package org.microg.nlp.api.sample; + +import android.location.Location; +import android.util.Log; +import org.microg.nlp.api.LocationBackendService; + +public class SampleBackendService extends LocationBackendService { + private static final String TAG = SampleBackendService.class.getName(); + + @Override + protected Location update() { + Location location = new Location("sample"); + location.setLatitude(42); + location.setLongitude(42); + location.setAccuracy(42); + Log.d(TAG, "I was asked for location and I answer: " + location); + return location; + } +} diff --git a/src/org/microg/nlp/Provider.java b/src/org/microg/nlp/Provider.java new file mode 100644 index 0000000..889284c --- /dev/null +++ b/src/org/microg/nlp/Provider.java @@ -0,0 +1,7 @@ +package org.microg.nlp; + +import android.os.IBinder; + +public interface Provider { + IBinder getBinder(); +} diff --git a/src/org/microg/nlp/ProviderService.java b/src/org/microg/nlp/ProviderService.java new file mode 100644 index 0000000..32c7f8c --- /dev/null +++ b/src/org/microg/nlp/ProviderService.java @@ -0,0 +1,53 @@ +package org.microg.nlp; + +import android.app.IntentService; +import android.content.Intent; +import android.os.IBinder; + +public abstract class ProviderService extends IntentService { + private Provider provider; + + /** + * Creates an ProviderService. Invoked by your subclass's constructor. + * + * @param tag Used for debugging. + */ + public ProviderService(String tag) { + super(tag); + } + + @Override + public void onCreate() { + provider = createProvider(); + } + + @Override + public IBinder onBind(Intent intent) { + return provider.getBinder(); + } + + @Override + public void onDestroy() { + provider = null; + } + + /** + * Create a {@link org.microg.nlp.Provider}. + * This is most likely only called once + * + * @return a new {@link org.microg.nlp.Provider} instance + */ + protected abstract Provider createProvider(); + + @Override + protected void onHandleIntent(Intent intent) { + // Default implementation is to do nothing + } + + /** + * @return the currently used {@link org.microg.nlp.Provider} instance + */ + protected Provider getCurrentProvider() { + return provider; + } +} diff --git a/src/org/microg/nlp/geocode/GeocodeProvider.java b/src/org/microg/nlp/geocode/GeocodeProvider.java new file mode 100644 index 0000000..7d6ae69 --- /dev/null +++ b/src/org/microg/nlp/geocode/GeocodeProvider.java @@ -0,0 +1,6 @@ +package org.microg.nlp.geocode; + +import org.microg.nlp.Provider; + +public interface GeocodeProvider extends Provider { +} diff --git a/src/org/microg/nlp/geocode/GeocodeProviderV1.java b/src/org/microg/nlp/geocode/GeocodeProviderV1.java new file mode 100644 index 0000000..842cbe4 --- /dev/null +++ b/src/org/microg/nlp/geocode/GeocodeProviderV1.java @@ -0,0 +1,22 @@ +package org.microg.nlp.geocode; + +import android.location.Address; +import android.location.GeocoderParams; +import com.android.location.provider.GeocodeProvider; + +import java.util.List; + +public class GeocodeProviderV1 extends GeocodeProvider implements org.microg.nlp.geocode.GeocodeProvider { + @Override + public String onGetFromLocation(double latitude, double longitude, int maxResults, GeocoderParams params, + List

addresses) { + return null; + } + + @Override + public String onGetFromLocationName(String locationName, double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude, int maxResults, + GeocoderParams params, List
addresses) { + return null; + } +} diff --git a/src/org/microg/nlp/geocode/GeocodeService.java b/src/org/microg/nlp/geocode/GeocodeService.java new file mode 100644 index 0000000..4a4853a --- /dev/null +++ b/src/org/microg/nlp/geocode/GeocodeService.java @@ -0,0 +1,17 @@ +package org.microg.nlp.geocode; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import org.microg.nlp.ProviderService; + +public abstract class GeocodeService extends ProviderService { + /** + * Creates an GeocodeService. Invoked by your subclass's constructor. + * + * @param tag Used for debugging. + */ + public GeocodeService(String tag) { + super(tag); + } +} diff --git a/src/org/microg/nlp/geocode/GeocodeServiceV1.java b/src/org/microg/nlp/geocode/GeocodeServiceV1.java new file mode 100644 index 0000000..afaa2b9 --- /dev/null +++ b/src/org/microg/nlp/geocode/GeocodeServiceV1.java @@ -0,0 +1,16 @@ +package org.microg.nlp.geocode; + +import org.microg.nlp.Provider; + +public class GeocodeServiceV1 extends GeocodeService { + private static final String TAG = GeocodeServiceV1.class.getName(); + + public GeocodeServiceV1() { + super(TAG); + } + + @Override + protected Provider createProvider() { + return new GeocodeProviderV1(); + } +} diff --git a/src/org/microg/nlp/location/BackendHelper.java b/src/org/microg/nlp/location/BackendHelper.java new file mode 100644 index 0000000..e4e7935 --- /dev/null +++ b/src/org/microg/nlp/location/BackendHelper.java @@ -0,0 +1,132 @@ +package org.microg.nlp.location; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.location.Location; +import android.os.*; +import android.util.Log; +import com.android.location.provider.LocationProviderBase; +import org.microg.nlp.api.LocationBackend; +import org.microg.nlp.api.LocationCallback; + +public class BackendHelper { + private static final String TAG = BackendHelper.class.getName(); + private final Context context; + private final LocationProvider provider; + private final Intent serviceIntent; + private final Connection connection = new Connection(); + private final Callback callback = new Callback(); + private LocationBackend backend; + private boolean updateWaiting; + private Location lastLocation; + private boolean bound; + + public BackendHelper(Context context, LocationProvider provider, Intent serviceIntent) { + this.context = context; + this.provider = provider; + this.serviceIntent = serviceIntent; + } + + public boolean bind() { + if (!bound) { + try { + context.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + Log.w(TAG, e); + return false; + } + } + return true; + } + + public void unbind() { + if (bound) { + try { + backend.close(); + context.unbindService(connection); + } catch (Exception e) { + Log.w(TAG, e); + } + } + } + + public Location getLastLocation() { + return lastLocation; + } + + public Location update() { + if (backend == null) { + Log.d(TAG, "Not (yet) bound."); + updateWaiting = true; + } else { + updateWaiting = false; + try { + setLastLocation(backend.update()); + provider.reportLocation(lastLocation); + } catch (RemoteException e) { + Log.w(TAG, e); + unbind(); + } + } + return lastLocation; + } + + private Location setLastLocation(Location location) { + if (location == null) { + return lastLocation; + } + if (location.getExtras() == null) { + location.setExtras(new Bundle()); + } + location.getExtras().putString("SERVICE_BACKEND_PROVIDER", location.getProvider()); + location.getExtras().putString("SERVICE_BACKEND_PACKAGE", serviceIntent.getPackage()); + location.setProvider("network"); + if (!location.hasAccuracy()) { + location.setAccuracy(50000); + } + if (location.getTime() <= 0) { + location.setTime(System.currentTimeMillis()); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + if (location.getElapsedRealtimeNanos() <= 0) { + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + } + } + location.getExtras().putParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION, new Location(location)); + lastLocation = location; + Log.v(TAG, "location=" + lastLocation); + return lastLocation; + } + + private class Connection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + bound = true; + backend = LocationBackend.Stub.asInterface(service); + try { + backend.open(callback); + if (updateWaiting) { + update(); + } + } catch (RemoteException e) { + Log.w(TAG, e); + unbind(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + backend = null; + bound = false; + } + } + + private class Callback extends LocationCallback.Stub { + @Override + public void report(Location location) throws RemoteException { + provider.reportLocation(setLastLocation(location)); + } + } +} diff --git a/src/org/microg/nlp/location/LocationProvider.java b/src/org/microg/nlp/location/LocationProvider.java new file mode 100644 index 0000000..2bfae99 --- /dev/null +++ b/src/org/microg/nlp/location/LocationProvider.java @@ -0,0 +1,12 @@ +package org.microg.nlp.location; + +import android.location.Location; +import org.microg.nlp.Provider; + +public interface LocationProvider extends Provider { + void onEnable(); + + void onDisable(); + + void reportLocation(Location location); +} diff --git a/src/org/microg/nlp/location/LocationProviderV2.java b/src/org/microg/nlp/location/LocationProviderV2.java new file mode 100644 index 0000000..ea102ed --- /dev/null +++ b/src/org/microg/nlp/location/LocationProviderV2.java @@ -0,0 +1,79 @@ +package org.microg.nlp.location; + +import android.content.Context; +import android.location.Criteria; +import android.os.Bundle; +import android.os.WorkSource; +import android.util.Log; +import com.android.location.provider.LocationProviderBase; +import com.android.location.provider.LocationRequestUnbundled; +import com.android.location.provider.ProviderPropertiesUnbundled; +import com.android.location.provider.ProviderRequestUnbundled; + +import static android.location.LocationProvider.AVAILABLE; + +public class LocationProviderV2 extends LocationProviderBase implements LocationProvider { + private static final String TAG = LocationProviderV2.class.getName(); + private static final ProviderPropertiesUnbundled props = ProviderPropertiesUnbundled.create( + false, // requiresNetwork + false, // requiresSatellite + false, // requiresCell + false, // hasMonetaryCost + true, // supportsAltitude + true, // supportsSpeed + true, // supportsBearing + Criteria.POWER_LOW, // powerRequirement + Criteria.ACCURACY_COARSE); // accuracy + private final ThreadHelper handler; + + public LocationProviderV2(Context context) { + super(TAG, props); + handler = new ThreadHelper(context, this); + } + + @Override + public void onDisable() { + } + + @Override + public void onEnable() { + } + + @Override + public int onGetStatus(Bundle extras) { + return AVAILABLE; + } + + @Override + public long onGetStatusUpdateTime() { + return 0; + } + + @Override + public void onSetRequest(ProviderRequestUnbundled requests, WorkSource source) { + Log.v(TAG, "onSetRequest: " + requests + " by " + source); + + long autoTime = Long.MAX_VALUE; + boolean autoUpdate = false; + for (LocationRequestUnbundled request : requests.getLocationRequests()) { + Log.v(TAG, "onSetRequest: request: " + request); + if (autoTime > request.getInterval()) { + autoTime = request.getInterval(); + } + autoUpdate = true; + } + + if (autoTime < 1500) { + // Limit to 1.5s + autoTime = 1500; + } + Log.v(TAG, "using autoUpdate=" + autoUpdate + " autoTime=" + autoTime); + + if (autoUpdate) { + handler.setTime(autoTime); + handler.enable(); + } else { + handler.disable(); + } + } +} diff --git a/src/org/microg/nlp/location/LocationService.java b/src/org/microg/nlp/location/LocationService.java new file mode 100644 index 0000000..0993169 --- /dev/null +++ b/src/org/microg/nlp/location/LocationService.java @@ -0,0 +1,41 @@ +package org.microg.nlp.location; + +import android.content.Intent; +import org.microg.nlp.Provider; +import org.microg.nlp.ProviderService; + +public abstract class LocationService extends ProviderService { + /** + * Creates an LocationService. Invoked by your subclass's constructor. + * + * @param tag Used for debugging. + */ + public LocationService(String tag) { + super(tag); + } + + @Override + protected void onHandleIntent(Intent intent) { + /* + * There is an undocumented way to send locations via intent in Google's LocationService. + * This intent based location is not secure, that's why it's not active here, + * but maybe we will add it in the future, could be a nice debugging feature :) + */ + + /* + Location location = intent.getParcelableExtra("location"); + if (nlprovider != null && location != null) { + nlprovider.reportLocation(location); + } + */ + } + + @Override + public boolean onUnbind(Intent intent) { + Provider provider = getCurrentProvider(); + if (provider instanceof LocationProvider) { + ((LocationProvider) provider).onDisable(); + } + return false; + } +} diff --git a/src/org/microg/nlp/location/LocationServiceV2.java b/src/org/microg/nlp/location/LocationServiceV2.java new file mode 100644 index 0000000..db3856b --- /dev/null +++ b/src/org/microg/nlp/location/LocationServiceV2.java @@ -0,0 +1,14 @@ +package org.microg.nlp.location; + +public class LocationServiceV2 extends LocationService { + private static final String TAG = LocationServiceV2.class.getName(); + + public LocationServiceV2() { + super(TAG); + } + + @Override + protected LocationProvider createProvider() { + return new LocationProviderV2(this); + } +} diff --git a/src/org/microg/nlp/location/ThreadHelper.java b/src/org/microg/nlp/location/ThreadHelper.java new file mode 100644 index 0000000..8c3a2e0 --- /dev/null +++ b/src/org/microg/nlp/location/ThreadHelper.java @@ -0,0 +1,56 @@ +package org.microg.nlp.location; + +import android.content.Context; +import android.content.Intent; +import org.microg.nlp.api.NlpApiConstants; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ThreadHelper implements Runnable { + private BackendHelper api; + private ScheduledThreadPoolExecutor executor; + private long time = 5000; // Initialize with 5s + private boolean enabled; + + public ThreadHelper(Context context, LocationProvider provider) { + api = new BackendHelper(context, provider, new Intent(NlpApiConstants.ACTION_LOCATION_BACKEND)); + } + + public void disable() { + if (executor != null) { + executor.shutdownNow(); + executor = null; + } + if (enabled) { + api.unbind(); + enabled = false; + } + } + + public void setTime(long time) { + this.time = time; + } + + public void reset() { + if (executor != null) { + executor.shutdownNow(); + executor = null; + } + executor = new ScheduledThreadPoolExecutor(1); + executor.scheduleAtFixedRate(this, 0, time, TimeUnit.MILLISECONDS); + } + + public void enable() { + if (!enabled) { + api.bind(); + enabled = true; + } + reset(); + } + + @Override + public void run() { + api.update(); + } +} diff --git a/src/org/microg/nlp/ui/LocationBackendConfig.java b/src/org/microg/nlp/ui/LocationBackendConfig.java new file mode 100644 index 0000000..65c69e7 --- /dev/null +++ b/src/org/microg/nlp/ui/LocationBackendConfig.java @@ -0,0 +1,91 @@ +package org.microg.nlp.ui; + +import android.app.ListActivity; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.*; +import org.microg.nlp.api.NlpApiConstants; + +import java.util.ArrayList; +import java.util.List; + +public class LocationBackendConfig extends ListActivity { + + private List activeBackends; + private Adapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + activeBackends = new ArrayList(); + List backends = new ArrayList(); + Intent intent = new Intent(NlpApiConstants.ACTION_LOCATION_BACKEND); + List resolveInfos = getPackageManager().queryIntentServices(intent, 0); + for (ResolveInfo info : resolveInfos) { + String packageName = info.serviceInfo.packageName; + String simpleName = String.valueOf(info.serviceInfo.loadLabel(getPackageManager())); + Drawable icon = info.serviceInfo.loadIcon(getPackageManager()); + backends.add(new KnownBackend(packageName, simpleName, icon)); + } + adapter = new Adapter(backends); + setListAdapter(adapter); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + KnownBackend backend = adapter.getItem(position); + if (activeBackends.contains(backend.packageName)) { + activeBackends.remove(backend.packageName); + } else { + activeBackends.add(backend.packageName); + } + adapter.notifyDataSetChanged(); + } + + private class Adapter extends ArrayAdapter { + public Adapter(List backends) { + super(LocationBackendConfig.this, android.R.layout.select_dialog_multichoice, android.R.id.text1, backends); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // User super class to create the View + View v = super.getView(position, convertView, parent); + CheckedTextView tv = (CheckedTextView) v.findViewById(android.R.id.text1); + + // Put the image on the TextView + tv.setCompoundDrawablesWithIntrinsicBounds(getItem(position).icon, null, + null, null); + + // Add margin between image and text (support various screen densities) + int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f); + tv.setCompoundDrawablePadding(dp10); + + tv.setChecked(activeBackends.contains(getItem(position).packageName)); + + return v; + } + } + + private class KnownBackend { + private String packageName; + private String simpleName; + private Drawable icon; + + public KnownBackend(String packageName, String simpleName, Drawable icon) { + this.packageName = packageName; + this.simpleName = simpleName; + this.icon = icon; + } + + @Override + public String toString() { + return simpleName; + } + } +} \ No newline at end of file