Initial commit
This commit is contained in:
commit
855ea472d3
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.iml
|
||||
gen
|
||||
bin
|
34
Android.mk
Normal file
34
Android.mk
Normal file
|
@ -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))
|
74
AndroidManifest.xml
Normal file
74
AndroidManifest.xml
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.microg.nlp">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/nlp_app_icon"
|
||||
android:label="@string/nlp_app_name">
|
||||
<uses-library
|
||||
android:name="com.android.location.provider"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Gingerbread / Ice Cream Sandwich -->
|
||||
<service
|
||||
android:name="org.microg.nlp.location.LocationServiceV1"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.location.NetworkLocationProvider" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="serviceVersion"
|
||||
android:value="1" />
|
||||
<meta-data
|
||||
android:name="version"
|
||||
android:value="1" />
|
||||
</service>
|
||||
|
||||
<!-- Jelly Bean / KitKat -->
|
||||
<service
|
||||
android:name="org.microg.nlp.location.LocationServiceV2"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<!-- KitKat changed the action name but nothing else, hence we handle it the same -->
|
||||
<action android:name="com.android.location.service.v3.NetworkLocationProvider" />
|
||||
<action android:name="com.android.location.service.v2.NetworkLocationProvider" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="serviceVersion"
|
||||
android:value="2" />
|
||||
<meta-data
|
||||
android:name="serviceIsMultiuser"
|
||||
android:value="false" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="org.microg.nlp.geocode.GeocodeServiceV1"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<!-- Jelly Bean changed the action name but nothing else, hence we handle it the same -->
|
||||
<action android:name="com.android.location.service.GeocodeProvider" />
|
||||
<action android:name="com.google.android.location.GeocodeProvider" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="serviceVersion"
|
||||
android:value="2" />
|
||||
<meta-data
|
||||
android:name="serviceIsMultiuser"
|
||||
android:value="false" />
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name="org.microg.nlp.ui.LocationBackendConfig"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Light">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
6
README.md
Normal file
6
README.md
Normal file
|
@ -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`
|
9
api/Android.mk
Normal file
9
api/Android.mk
Normal file
|
@ -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)
|
4
api/AndroidManifest.xml
Normal file
4
api/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.microg.nlp.api">
|
||||
|
||||
</manifest>
|
10
api/src/org/microg/nlp/api/LocationBackend.aidl
Normal file
10
api/src/org/microg/nlp/api/LocationBackend.aidl
Normal file
|
@ -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();
|
||||
}
|
71
api/src/org/microg/nlp/api/LocationBackendService.java
Normal file
71
api/src/org/microg/nlp/api/LocationBackendService.java
Normal file
|
@ -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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
7
api/src/org/microg/nlp/api/LocationCallback.aidl
Normal file
7
api/src/org/microg/nlp/api/LocationCallback.aidl
Normal file
|
@ -0,0 +1,7 @@
|
|||
package org.microg.nlp.api;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
interface LocationCallback {
|
||||
void report(in Location location);
|
||||
}
|
5
api/src/org/microg/nlp/api/NlpApiConstants.java
Normal file
5
api/src/org/microg/nlp/api/NlpApiConstants.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package org.microg.nlp.api;
|
||||
|
||||
public class NlpApiConstants {
|
||||
public static final String ACTION_LOCATION_BACKEND = "org.microg.nlp.LOCATION_BACKEND";
|
||||
}
|
BIN
res/drawable-hdpi/nlp_app_icon.png
Normal file
BIN
res/drawable-hdpi/nlp_app_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
res/drawable-mdpi/nlp_app_icon.png
Normal file
BIN
res/drawable-mdpi/nlp_app_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
res/drawable-xhdpi/nlp_app_icon.png
Normal file
BIN
res/drawable-xhdpi/nlp_app_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
4
res/values/strings.xml
Normal file
4
res/values/strings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="nlp_app_name">NLP Controller</string>
|
||||
</resources>
|
17
sample/AndroidManifest.xml
Normal file
17
sample/AndroidManifest.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.microg.nlp.api.sample">
|
||||
|
||||
<uses-sdk android:minSdkVersion="19" />
|
||||
<application
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name">
|
||||
<service
|
||||
android:name=".SampleBackendService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.microg.nlp.LOCATION_BACKEND" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
BIN
sample/res/drawable/icon.png
Normal file
BIN
sample/res/drawable/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 990 B |
4
sample/res/values/strings.xml
Normal file
4
sample/res/values/strings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">NetworkLocationV2-SamplePlugin</string>
|
||||
</resources>
|
|
@ -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;
|
||||
}
|
||||
}
|
7
src/org/microg/nlp/Provider.java
Normal file
7
src/org/microg/nlp/Provider.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package org.microg.nlp;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
public interface Provider {
|
||||
IBinder getBinder();
|
||||
}
|
53
src/org/microg/nlp/ProviderService.java
Normal file
53
src/org/microg/nlp/ProviderService.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
6
src/org/microg/nlp/geocode/GeocodeProvider.java
Normal file
6
src/org/microg/nlp/geocode/GeocodeProvider.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package org.microg.nlp.geocode;
|
||||
|
||||
import org.microg.nlp.Provider;
|
||||
|
||||
public interface GeocodeProvider extends Provider {
|
||||
}
|
22
src/org/microg/nlp/geocode/GeocodeProviderV1.java
Normal file
22
src/org/microg/nlp/geocode/GeocodeProviderV1.java
Normal file
|
@ -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<Address> addresses) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onGetFromLocationName(String locationName, double lowerLeftLatitude, double lowerLeftLongitude,
|
||||
double upperRightLatitude, double upperRightLongitude, int maxResults,
|
||||
GeocoderParams params, List<Address> addresses) {
|
||||
return null;
|
||||
}
|
||||
}
|
17
src/org/microg/nlp/geocode/GeocodeService.java
Normal file
17
src/org/microg/nlp/geocode/GeocodeService.java
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
16
src/org/microg/nlp/geocode/GeocodeServiceV1.java
Normal file
16
src/org/microg/nlp/geocode/GeocodeServiceV1.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
132
src/org/microg/nlp/location/BackendHelper.java
Normal file
132
src/org/microg/nlp/location/BackendHelper.java
Normal file
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
12
src/org/microg/nlp/location/LocationProvider.java
Normal file
12
src/org/microg/nlp/location/LocationProvider.java
Normal file
|
@ -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);
|
||||
}
|
79
src/org/microg/nlp/location/LocationProviderV2.java
Normal file
79
src/org/microg/nlp/location/LocationProviderV2.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
41
src/org/microg/nlp/location/LocationService.java
Normal file
41
src/org/microg/nlp/location/LocationService.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
14
src/org/microg/nlp/location/LocationServiceV2.java
Normal file
14
src/org/microg/nlp/location/LocationServiceV2.java
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
56
src/org/microg/nlp/location/ThreadHelper.java
Normal file
56
src/org/microg/nlp/location/ThreadHelper.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
91
src/org/microg/nlp/ui/LocationBackendConfig.java
Normal file
91
src/org/microg/nlp/ui/LocationBackendConfig.java
Normal file
|
@ -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<String> activeBackends;
|
||||
private Adapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
activeBackends = new ArrayList<String>();
|
||||
List<KnownBackend> backends = new ArrayList<KnownBackend>();
|
||||
Intent intent = new Intent(NlpApiConstants.ACTION_LOCATION_BACKEND);
|
||||
List<ResolveInfo> 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<KnownBackend> {
|
||||
public Adapter(List<KnownBackend> 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue