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