添加libgpsrelaysentinel类库初始源码
This commit is contained in:
@@ -56,6 +56,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':libgpsrelaysentinel')
|
||||
|
||||
api 'com.google.code.gson:gson:2.10.1'
|
||||
|
||||
|
||||
@@ -9,12 +9,15 @@ import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.manager.GpsSubscribeManager;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.manager.SubscribeLocationManager;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeMsg;
|
||||
import java.util.Map;
|
||||
|
||||
public class MainService extends Service {
|
||||
|
||||
@@ -72,6 +75,31 @@ public class MainService extends Service {
|
||||
String gpsInfo = "Lat: " + location.getLatitude() + ", Lng: " + location.getLongitude();
|
||||
LogUtils.d(TAG, "Location changed: " + gpsInfo);
|
||||
updateNotification(gpsInfo);
|
||||
|
||||
//管理器初始化
|
||||
GpsSubscribeManager subscribeManager = GpsSubscribeManager.getInstance();
|
||||
SubscribeLocationManager locationManager = SubscribeLocationManager.getInstance();
|
||||
|
||||
//遍历所有订阅者做距离判断+定点更新
|
||||
Map<String, GpsSubscribeMsg> subscribeMap = subscribeManager.getSubscribeMap();
|
||||
for (Map.Entry<String, GpsSubscribeMsg> entry : subscribeMap.entrySet()) {
|
||||
String sid = entry.getKey();
|
||||
GpsSubscribeMsg subscribeMsg = entry.getValue();
|
||||
|
||||
double nowLat = location.getLatitude();
|
||||
double nowLng = location.getLongitude();
|
||||
|
||||
//判断是否满足推送
|
||||
boolean canPush = locationManager.isNeedPush(sid, nowLat, nowLng);
|
||||
if (canPush) {
|
||||
//执行发送GPS广播
|
||||
//sendGpsBroadcast(...);
|
||||
|
||||
//推送成功立刻刷新订阅者基准坐标
|
||||
locationManager.updateSubscriberPoint(sid, nowLat, nowLng);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
1
libgpsrelaysentinel/.gitignore
vendored
Normal file
1
libgpsrelaysentinel/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
25
libgpsrelaysentinel/build.gradle
Normal file
25
libgpsrelaysentinel/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply from: '../.winboll/winboll_lib_build.gradle'
|
||||
apply from: '../.winboll/winboll_lint_build.gradle'
|
||||
|
||||
android {
|
||||
// 适配MIUI12
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
8
libgpsrelaysentinel/build.properties
Normal file
8
libgpsrelaysentinel/build.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Fri May 01 17:09:11 HKT 2026
|
||||
stageCount=57
|
||||
libraryProject=libdebugtemp
|
||||
baseVersion=15.0
|
||||
publishVersion=15.0.56
|
||||
buildCount=0
|
||||
baseBetaVersion=15.0.57
|
||||
17
libgpsrelaysentinel/proguard-rules.pro
vendored
Normal file
17
libgpsrelaysentinel/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:/tools/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
27
libgpsrelaysentinel/src/main/AndroidManifest.xml
Normal file
27
libgpsrelaysentinel/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cc.winboll.studio.libgpsrelaysentinel">
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".service.GpsSubscribeReceiverService"
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="cc.winboll.studio.libgpsrelaysentinel.action.RECEIVE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name=".receiver.GpsSubscribeObserverReceiver">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name=".receiver.GpsSubscribeObserverReceiver"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,75 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.manager;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:25
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeConst;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeMsg;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeResult;
|
||||
|
||||
public final class GpsSubscribeManager {
|
||||
|
||||
private static GpsSubscribeManager instance;
|
||||
private final Map<String,GpsSubscribeMsg> subscribeMap;
|
||||
private Context appContext;
|
||||
|
||||
private GpsSubscribeManager(){
|
||||
subscribeMap = new HashMap<String, GpsSubscribeMsg>();
|
||||
}
|
||||
|
||||
public static GpsSubscribeManager getInstance(){
|
||||
if(instance == null){
|
||||
instance = new GpsSubscribeManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void initContext(final Context context){
|
||||
this.appContext = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public void addSubscribe(final GpsSubscribeMsg subscribeMsg){
|
||||
if(subscribeMsg == null){
|
||||
return;
|
||||
}
|
||||
subscribeMap.put(subscribeMsg.getSubscribeUniqueId(),subscribeMsg);
|
||||
}
|
||||
|
||||
public void removeSubscribe(final String sid){
|
||||
if(sid == null){
|
||||
return;
|
||||
}
|
||||
subscribeMap.remove(sid);
|
||||
SubscribeLocationManager.getInstance().removeSubscribe(sid);
|
||||
}
|
||||
|
||||
public boolean isSubscribeExist(final String sid){
|
||||
return subscribeMap.containsKey(sid);
|
||||
}
|
||||
|
||||
public void sendSubscribeResult(final GpsSubscribeResult result){
|
||||
if(appContext == null || result == null){
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(GpsSubscribeConst.ACTION_SUBSCRIBE_CALLBACK);
|
||||
intent.putExtra("data",result);
|
||||
appContext.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public void clearAllSubscribe(){
|
||||
subscribeMap.clear();
|
||||
SubscribeLocationManager.getInstance().clearAll();
|
||||
}
|
||||
|
||||
public Map<String, GpsSubscribeMsg> getSubscribeMap() {
|
||||
return subscribeMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.manager;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:26
|
||||
*/
|
||||
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeConst;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeMsg;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.LocationPoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class SubscribeLocationManager {
|
||||
|
||||
private static SubscribeLocationManager instance;
|
||||
private final Map<String,GpsSubscribeMsg> subscribeConfigMap;
|
||||
private final Map<String,LocationPoint> subscriberPointMap;
|
||||
|
||||
private SubscribeLocationManager(){
|
||||
subscribeConfigMap = new HashMap<String, GpsSubscribeMsg>();
|
||||
subscriberPointMap = new HashMap<String, LocationPoint>();
|
||||
}
|
||||
|
||||
public static SubscribeLocationManager getInstance(){
|
||||
if(instance == null){
|
||||
instance = new SubscribeLocationManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void putSubscribeConfig(final String sid,final GpsSubscribeMsg msg){
|
||||
subscribeConfigMap.put(sid,msg);
|
||||
}
|
||||
|
||||
public void initSubscriberPoint(final String sid,double lat,double lng){
|
||||
subscriberPointMap.put(sid,new LocationPoint(lat,lng,System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public void updateSubscriberPoint(final String sid,double lat,double lng){
|
||||
subscriberPointMap.put(sid,new LocationPoint(lat,lng,System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public LocationPoint getLastPoint(final String sid){
|
||||
return subscriberPointMap.get(sid);
|
||||
}
|
||||
|
||||
public GpsSubscribeMsg getSubscribeConfig(final String sid){
|
||||
return subscribeConfigMap.get(sid);
|
||||
}
|
||||
|
||||
public boolean isNeedPush(final String sid,double nowLat,double nowLng){
|
||||
GpsSubscribeMsg config = getSubscribeConfig(sid);
|
||||
if(config == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(config.getSubscribeMode() == GpsSubscribeConst.SUB_TYPE_ALL){
|
||||
return true;
|
||||
}
|
||||
|
||||
LocationPoint lastPoint = getLastPoint(sid);
|
||||
if(lastPoint == null){
|
||||
return true;
|
||||
}
|
||||
|
||||
double distance = calculateDistance(
|
||||
lastPoint.getLatitude(),lastPoint.getLongitude(),
|
||||
nowLat,nowLng
|
||||
);
|
||||
return distance >= config.getStepDistanceM();
|
||||
}
|
||||
|
||||
private double calculateDistance(double lat1,double lng1,double lat2,double lng2){
|
||||
double radLat1 = Math.toRadians(lat1);
|
||||
double radLat2 = Math.toRadians(lat2);
|
||||
double radLng1 = Math.toRadians(lng1);
|
||||
double radLng2 = Math.toRadians(lng2);
|
||||
|
||||
double latDiff = radLat1 - radLat2;
|
||||
double lngDiff = radLng1 - radLng2;
|
||||
|
||||
double result = 2 * Math.asin(Math.sqrt(
|
||||
Math.pow(Math.sin(latDiff / 2),2)
|
||||
+ Math.cos(radLat1) * Math.cos(radLat2)
|
||||
* Math.pow(Math.sin(lngDiff / 2),2)
|
||||
));
|
||||
result = result * GpsSubscribeConst.EARTH_RADIUS;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeSubscribe(final String sid){
|
||||
subscribeConfigMap.remove(sid);
|
||||
subscriberPointMap.remove(sid);
|
||||
}
|
||||
|
||||
public void clearAll(){
|
||||
subscribeConfigMap.clear();
|
||||
subscriberPointMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.model;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:22
|
||||
* WinBoLL Studio
|
||||
* Java7 | API26-30
|
||||
*/
|
||||
public final class GpsSubscribeConst {
|
||||
|
||||
// 新增:GPS定位推送广播
|
||||
public static final String ACTION_GPS_LOCATION = "cc.winboll.studio.ACTION_GPS_LOCATION";
|
||||
|
||||
//订阅运行模式
|
||||
public static final int SUB_TYPE_ALL = 1;
|
||||
public static final int SUB_TYPE_STEP_DISTANCE = 2;
|
||||
|
||||
//原始数据订阅类型
|
||||
public static final int SUBSCRIBE_TYPE_LOCATION = 1;
|
||||
public static final int SUBSCRIBE_TYPE_SATELLITE = 2;
|
||||
public static final int SUBSCRIBE_TYPE_NMEA = 3;
|
||||
|
||||
//订阅返回码
|
||||
public static final int RESULT_SUCCESS = 0;
|
||||
public static final int RESULT_PERMISSION_DENY = 1;
|
||||
public static final int RESULT_PARAM_ERROR = 2;
|
||||
public static final int RESULT_GPS_NOT_AVAILABLE = 3;
|
||||
public static final int RESULT_SYSTEM_LIMIT = 4;
|
||||
|
||||
//GPS设备状态
|
||||
public static final int GPS_STATE_CLOSE = 0;
|
||||
public static final int GPS_STATE_SCANNING = 1;
|
||||
public static final int GPS_STATE_LOCATED = 2;
|
||||
public static final int GPS_STATE_SIGNAL_WEAK = 3;
|
||||
|
||||
//广播Action
|
||||
public static final String ACTION_SUBSCRIBE_REQUEST = "cc.winboll.studio.GPS_SUBSCRIBE_REQUEST";
|
||||
public static final String ACTION_SUBSCRIBE_CALLBACK = "cc.winboll.studio.GPS_SUBSCRIBE_CALLBACK";
|
||||
|
||||
//超时毫秒
|
||||
public static final long SUBSCRIBE_TIME_OUT = 5000;
|
||||
|
||||
//地球半径 距离计算常量
|
||||
public static final double EARTH_RADIUS = 6378137.0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.model;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:24
|
||||
*/
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public final class GpsSubscribeMsg implements Parcelable {
|
||||
|
||||
private final String subscribePackage;
|
||||
private final int subscribeMode;
|
||||
private final float stepDistanceM;
|
||||
|
||||
private final int subscribeType;
|
||||
private final long updateInterval;
|
||||
private final float minDistance;
|
||||
private final boolean backgroundPush;
|
||||
private final String subscribeUniqueId;
|
||||
|
||||
public GpsSubscribeMsg(String subscribePackage,
|
||||
int subscribeMode,
|
||||
float stepDistanceM,
|
||||
int subscribeType,
|
||||
long updateInterval,
|
||||
float minDistance,
|
||||
boolean backgroundPush,
|
||||
String subscribeUniqueId) {
|
||||
this.subscribePackage = subscribePackage;
|
||||
this.subscribeMode = subscribeMode;
|
||||
this.stepDistanceM = stepDistanceM;
|
||||
this.subscribeType = subscribeType;
|
||||
this.updateInterval = updateInterval;
|
||||
this.minDistance = minDistance;
|
||||
this.backgroundPush = backgroundPush;
|
||||
this.subscribeUniqueId = subscribeUniqueId;
|
||||
}
|
||||
|
||||
public String getSubscribePackage() {
|
||||
return subscribePackage;
|
||||
}
|
||||
|
||||
public int getSubscribeMode() {
|
||||
return subscribeMode;
|
||||
}
|
||||
|
||||
public float getStepDistanceM() {
|
||||
return stepDistanceM;
|
||||
}
|
||||
|
||||
public int getSubscribeType() {
|
||||
return subscribeType;
|
||||
}
|
||||
|
||||
public long getUpdateInterval() {
|
||||
return updateInterval;
|
||||
}
|
||||
|
||||
public float getMinDistance() {
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
public boolean isBackgroundPush() {
|
||||
return backgroundPush;
|
||||
}
|
||||
|
||||
public String getSubscribeUniqueId() {
|
||||
return subscribeUniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(subscribePackage);
|
||||
dest.writeInt(subscribeMode);
|
||||
dest.writeFloat(stepDistanceM);
|
||||
dest.writeInt(subscribeType);
|
||||
dest.writeLong(updateInterval);
|
||||
dest.writeFloat(minDistance);
|
||||
dest.writeByte((byte) (backgroundPush ? 1 : 0));
|
||||
dest.writeString(subscribeUniqueId);
|
||||
}
|
||||
|
||||
public static final Creator<GpsSubscribeMsg> CREATOR = new Creator<GpsSubscribeMsg>() {
|
||||
@Override
|
||||
public GpsSubscribeMsg createFromParcel(Parcel in) {
|
||||
return new GpsSubscribeMsg(
|
||||
in.readString(),
|
||||
in.readInt(),
|
||||
in.readFloat(),
|
||||
in.readInt(),
|
||||
in.readLong(),
|
||||
in.readFloat(),
|
||||
in.readByte() == 1,
|
||||
in.readString()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GpsSubscribeMsg[] newArray(int size) {
|
||||
return new GpsSubscribeMsg[size];
|
||||
}
|
||||
};
|
||||
|
||||
public Bundle convertToBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("pkg", subscribePackage);
|
||||
bundle.putInt("subMode",subscribeMode);
|
||||
bundle.putFloat("stepM",stepDistanceM);
|
||||
bundle.putInt("type", subscribeType);
|
||||
bundle.putLong("interval", updateInterval);
|
||||
bundle.putFloat("distance", minDistance);
|
||||
bundle.putBoolean("bgPush", backgroundPush);
|
||||
bundle.putString("sid", subscribeUniqueId);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public static GpsSubscribeMsg createByBundle(Bundle bundle) {
|
||||
return new GpsSubscribeMsg(
|
||||
bundle.getString("pkg"),
|
||||
bundle.getInt("subMode"),
|
||||
bundle.getFloat("stepM"),
|
||||
bundle.getInt("type"),
|
||||
bundle.getLong("interval"),
|
||||
bundle.getFloat("distance"),
|
||||
bundle.getBoolean("bgPush"),
|
||||
bundle.getString("sid")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.model;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:25
|
||||
*/
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public final class GpsSubscribeResult implements Parcelable {
|
||||
|
||||
private final String subscribeUniqueId;
|
||||
private final int resultCode;
|
||||
private final String resultDesc;
|
||||
private final int gpsRunningState;
|
||||
private final long realEffectiveInterval;
|
||||
private final long currentTimeStamp;
|
||||
|
||||
public GpsSubscribeResult(String subscribeUniqueId,
|
||||
int resultCode,
|
||||
String resultDesc,
|
||||
int gpsRunningState,
|
||||
long realEffectiveInterval,
|
||||
long currentTimeStamp) {
|
||||
this.subscribeUniqueId = subscribeUniqueId;
|
||||
this.resultCode = resultCode;
|
||||
this.resultDesc = resultDesc;
|
||||
this.gpsRunningState = gpsRunningState;
|
||||
this.realEffectiveInterval = realEffectiveInterval;
|
||||
this.currentTimeStamp = currentTimeStamp;
|
||||
}
|
||||
|
||||
public String getSubscribeUniqueId() {
|
||||
return subscribeUniqueId;
|
||||
}
|
||||
|
||||
public int getResultCode() {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
public String getResultDesc() {
|
||||
return resultDesc;
|
||||
}
|
||||
|
||||
public int getGpsRunningState() {
|
||||
return gpsRunningState;
|
||||
}
|
||||
|
||||
public long getRealEffectiveInterval() {
|
||||
return realEffectiveInterval;
|
||||
}
|
||||
|
||||
public long getCurrentTimeStamp() {
|
||||
return currentTimeStamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(subscribeUniqueId);
|
||||
dest.writeInt(resultCode);
|
||||
dest.writeString(resultDesc);
|
||||
dest.writeInt(gpsRunningState);
|
||||
dest.writeLong(realEffectiveInterval);
|
||||
dest.writeLong(currentTimeStamp);
|
||||
}
|
||||
|
||||
public static final Creator<GpsSubscribeResult> CREATOR = new Creator<GpsSubscribeResult>() {
|
||||
@Override
|
||||
public GpsSubscribeResult createFromParcel(Parcel in) {
|
||||
return new GpsSubscribeResult(
|
||||
in.readString(),
|
||||
in.readInt(),
|
||||
in.readString(),
|
||||
in.readInt(),
|
||||
in.readLong(),
|
||||
in.readLong()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GpsSubscribeResult[] newArray(int size) {
|
||||
return new GpsSubscribeResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
public Bundle convertToBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("sid", subscribeUniqueId);
|
||||
bundle.putInt("code", resultCode);
|
||||
bundle.putString("desc", resultDesc);
|
||||
bundle.putInt("gpsState", gpsRunningState);
|
||||
bundle.putLong("realInterval", realEffectiveInterval);
|
||||
bundle.putLong("time", currentTimeStamp);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public static GpsSubscribeResult createByBundle(Bundle bundle) {
|
||||
return new GpsSubscribeResult(
|
||||
bundle.getString("sid"),
|
||||
bundle.getInt("code"),
|
||||
bundle.getString("desc"),
|
||||
bundle.getInt("gpsState"),
|
||||
bundle.getLong("realInterval"),
|
||||
bundle.getLong("time")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.model;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:23
|
||||
* 订阅者基准定点坐标
|
||||
* 每次推送成功自动更新
|
||||
*/
|
||||
public final class LocationPoint {
|
||||
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
private final long recordTime;
|
||||
|
||||
public LocationPoint(double latitude, double longitude, long recordTime) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.recordTime = recordTime;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public long getRecordTime() {
|
||||
return recordTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:27
|
||||
*/
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeConst;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeResult;
|
||||
|
||||
public final class GpsSubscribeObserverReceiver extends BroadcastReceiver {
|
||||
|
||||
private OnSubscribeResultListener listener;
|
||||
|
||||
public void setOnSubscribeResultListener(OnSubscribeResultListener listener){
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if(GpsSubscribeConst.ACTION_SUBSCRIBE_CALLBACK.equals(action)){
|
||||
GpsSubscribeResult result = intent.getParcelableExtra("data");
|
||||
if(listener != null && result != null){
|
||||
listener.onResultBack(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnSubscribeResultListener{
|
||||
void onResultBack(GpsSubscribeResult result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:46
|
||||
*/
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeConst;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeMsg;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeResult;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.LocationPoint;
|
||||
|
||||
/**
|
||||
* 对外消息接收服务:外部App可bind或start
|
||||
* 收到GPS消息后,通过本地广播回调给外部App
|
||||
*/
|
||||
public final class GpsSubscribeReceiverService extends Service {
|
||||
|
||||
// 外部回调监听
|
||||
public interface GpsMessageListener {
|
||||
void onGpsLocation(LocationPoint point, GpsSubscribeMsg config);
|
||||
void onSubscribeResult(GpsSubscribeResult result);
|
||||
}
|
||||
|
||||
private final List<GpsMessageListener> listeners = new CopyOnWriteArrayList<GpsMessageListener>();
|
||||
private final IBinder localBinder = new LocalBinder();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
// 外部App绑定服务
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return localBinder;
|
||||
}
|
||||
|
||||
// 外部App startService 入口:接收订阅请求
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent != null && intent.getParcelableExtra("req") != null) {
|
||||
GpsSubscribeMsg msg = intent.getParcelableExtra("req");
|
||||
handleSubscribeRequest(msg);
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
// 处理订阅请求:发送给管理器,并回执
|
||||
private void handleSubscribeRequest(final GpsSubscribeMsg msg) {
|
||||
// 加入订阅管理
|
||||
cc.winboll.studio.libgpsrelaysentinel.manager.GpsSubscribeManager
|
||||
.getInstance().addSubscribe(msg);
|
||||
cc.winboll.studio.libgpsrelaysentinel.manager.SubscribeLocationManager
|
||||
.getInstance().putSubscribeConfig(msg.getSubscribeUniqueId(), msg);
|
||||
|
||||
// 回执成功
|
||||
GpsSubscribeResult result = new GpsSubscribeResult(
|
||||
msg.getSubscribeUniqueId(),
|
||||
GpsSubscribeConst.RESULT_SUCCESS,
|
||||
"subscribe ok",
|
||||
GpsSubscribeConst.GPS_STATE_LOCATED,
|
||||
1000,
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
sendSubscribeResultBroadcast(result);
|
||||
notifySubscribeResult(result);
|
||||
}
|
||||
|
||||
// 供内部(GPS服务)调用:推送定位消息
|
||||
public void pushLocation(final LocationPoint point, final GpsSubscribeMsg config) {
|
||||
sendLocationBroadcast(point, config);
|
||||
notifyGpsLocation(point, config);
|
||||
}
|
||||
|
||||
// ---------- 广播回调(跨进程/外部App接收) ----------
|
||||
private void sendLocationBroadcast(final LocationPoint point, final GpsSubscribeMsg config) {
|
||||
Intent intent = new Intent(GpsSubscribeConst.ACTION_GPS_LOCATION);
|
||||
intent.putExtra("point", point);
|
||||
intent.putExtra("config", config);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void sendSubscribeResultBroadcast(final GpsSubscribeResult result) {
|
||||
Intent intent = new Intent(GpsSubscribeConst.ACTION_SUBSCRIBE_CALLBACK);
|
||||
intent.putExtra("data", result);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
// ---------- 本地Binder(同进程直接回调) ----------
|
||||
public class LocalBinder extends Binder {
|
||||
public GpsSubscribeReceiverService getService() {
|
||||
return GpsSubscribeReceiverService.this;
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(final GpsMessageListener l) {
|
||||
if (l != null && !listeners.contains(l)) {
|
||||
listeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(final GpsMessageListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
private void notifyGpsLocation(final LocationPoint point, final GpsSubscribeMsg config) {
|
||||
for (GpsMessageListener l : listeners) {
|
||||
l.onGpsLocation(point, config);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifySubscribeResult(final GpsSubscribeResult result) {
|
||||
for (GpsMessageListener l : listeners) {
|
||||
l.onSubscribeResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
listeners.clear();
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.util;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:26
|
||||
*/
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
public final class TimeCountUtil {
|
||||
|
||||
private final Handler mHandler;
|
||||
private long totalTime;
|
||||
private boolean isRunning;
|
||||
public static final int COUNT_FINISH = 1001;
|
||||
|
||||
public TimeCountUtil(final OnCountListener listener) {
|
||||
mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if(msg.what == COUNT_FINISH){
|
||||
isRunning = false;
|
||||
if(listener != null){
|
||||
listener.onTimeOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void start(long time){
|
||||
if(isRunning){
|
||||
return;
|
||||
}
|
||||
totalTime = time;
|
||||
isRunning = true;
|
||||
mHandler.sendEmptyMessageDelayed(COUNT_FINISH,totalTime);
|
||||
}
|
||||
|
||||
public void cancel(){
|
||||
mHandler.removeMessages(COUNT_FINISH);
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
public interface OnCountListener{
|
||||
void onTimeOut();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
package cc.winboll.studio.libgpsrelaysentinel.view;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/05/07 10:27
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.R;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeConst;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeMsg;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.model.GpsSubscribeResult;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.receiver.GpsSubscribeObserverReceiver;
|
||||
import cc.winboll.studio.libgpsrelaysentinel.util.TimeCountUtil;
|
||||
|
||||
public final class GpsSubscribeControlView extends LinearLayout {
|
||||
|
||||
private RadioGroup rgSubMode;
|
||||
private RadioButton rbAll;
|
||||
private RadioButton rbStep;
|
||||
private LinearLayout layoutStepSetting;
|
||||
private EditText etStepMeter;
|
||||
|
||||
private Switch mSwitchSubscribe;
|
||||
private TextView mTvCountTip;
|
||||
|
||||
private TimeCountUtil mTimeCountUtil;
|
||||
private GpsSubscribeObserverReceiver mResultReceiver;
|
||||
private String currentSubscribeSid;
|
||||
private boolean isSubscribeSuccess;
|
||||
|
||||
public GpsSubscribeControlView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
public GpsSubscribeControlView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView(){
|
||||
setOrientation(VERTICAL);
|
||||
inflate(getContext(),R.layout.view_gps_subscribe_control,this);
|
||||
|
||||
rgSubMode = findViewById(R.id.rg_sub_mode);
|
||||
rbAll = findViewById(R.id.rb_all);
|
||||
rbStep = findViewById(R.id.rb_step);
|
||||
layoutStepSetting = findViewById(R.id.layout_step_setting);
|
||||
etStepMeter = findViewById(R.id.et_step_meter);
|
||||
|
||||
mSwitchSubscribe = findViewById(R.id.switch_subscribe);
|
||||
mTvCountTip = findViewById(R.id.tv_count_tip);
|
||||
|
||||
initModeSwitch();
|
||||
initCountUtil();
|
||||
initReceiver();
|
||||
initSwitchEvent();
|
||||
}
|
||||
|
||||
private void initModeSwitch(){
|
||||
rgSubMode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(RadioGroup group, int checkedId) {
|
||||
layoutStepSetting.setVisibility(checkedId == R.id.rb_step ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initCountUtil(){
|
||||
mTimeCountUtil = new TimeCountUtil(new TimeCountUtil.OnCountListener() {
|
||||
@Override
|
||||
public void onTimeOut() {
|
||||
if(!isSubscribeSuccess){
|
||||
mSwitchSubscribe.setChecked(false);
|
||||
mTvCountTip.setText("订阅超时,已自动关闭");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initReceiver(){
|
||||
mResultReceiver = new GpsSubscribeObserverReceiver();
|
||||
mResultReceiver.setOnSubscribeResultListener(new GpsSubscribeObserverReceiver.OnSubscribeResultListener() {
|
||||
@Override
|
||||
public void onResultBack(GpsSubscribeResult result) {
|
||||
if(currentSubscribeSid.equals(result.getSubscribeUniqueId())){
|
||||
isSubscribeSuccess = true;
|
||||
mTimeCountUtil.cancel();
|
||||
mTvCountTip.setText("订阅已生效,通讯正常");
|
||||
}
|
||||
}
|
||||
});
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(GpsSubscribeConst.ACTION_SUBSCRIBE_CALLBACK);
|
||||
getContext().registerReceiver(mResultReceiver,filter);
|
||||
}
|
||||
|
||||
private void initSwitchEvent(){
|
||||
mSwitchSubscribe.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if(isChecked){
|
||||
startSubscribe();
|
||||
}else{
|
||||
stopSubscribe();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startSubscribe(){
|
||||
isSubscribeSuccess = false;
|
||||
currentSubscribeSid = UUID.randomUUID().toString();
|
||||
mTvCountTip.setText("等待订阅返回中...");
|
||||
|
||||
int subMode = GpsSubscribeConst.SUB_TYPE_ALL;
|
||||
float stepMeter = 10.0f;
|
||||
|
||||
if(rbStep.isChecked()){
|
||||
subMode = GpsSubscribeConst.SUB_TYPE_STEP_DISTANCE;
|
||||
try{
|
||||
stepMeter = Float.parseFloat(etStepMeter.getText().toString().trim());
|
||||
}catch (Exception e){
|
||||
stepMeter = 10.0f;
|
||||
}
|
||||
}
|
||||
|
||||
GpsSubscribeMsg msg = new GpsSubscribeMsg(
|
||||
getContext().getPackageName(),
|
||||
subMode,
|
||||
stepMeter,
|
||||
GpsSubscribeConst.SUBSCRIBE_TYPE_LOCATION,
|
||||
1000,
|
||||
1.0f,
|
||||
true,
|
||||
currentSubscribeSid
|
||||
);
|
||||
|
||||
Intent intent = new Intent(GpsSubscribeConst.ACTION_SUBSCRIBE_REQUEST);
|
||||
intent.putExtra("req",msg);
|
||||
getContext().sendBroadcast(intent);
|
||||
|
||||
mTimeCountUtil.start(GpsSubscribeConst.SUBSCRIBE_TIME_OUT);
|
||||
}
|
||||
|
||||
private void stopSubscribe(){
|
||||
mTimeCountUtil.cancel();
|
||||
isSubscribeSuccess = false;
|
||||
mTvCountTip.setText("订阅已关闭");
|
||||
}
|
||||
|
||||
public void release(){
|
||||
mTimeCountUtil.cancel();
|
||||
if(mResultReceiver != null){
|
||||
getContext().unregisterReceiver(mResultReceiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
libgpsrelaysentinel/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
BIN
libgpsrelaysentinel/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
BIN
libgpsrelaysentinel/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
BIN
libgpsrelaysentinel/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
libgpsrelaysentinel/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
BIN
libgpsrelaysentinel/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
libgpsrelaysentinel/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
BIN
libgpsrelaysentinel/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="订阅模式:"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_sub_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="全消息订阅"
|
||||
android:checked="true"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_step"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="步长订阅"/>
|
||||
</RadioGroup>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_step_setting"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="移动步长阈值(米):"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_step_meter"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal"
|
||||
android:text="10"
|
||||
android:gravity="center"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="GPS订阅总开关"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch_subscribe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_count_tip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="未订阅"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#666666"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
5
libgpsrelaysentinel/src/main/res/values-v21/styles.xml
Normal file
5
libgpsrelaysentinel/src/main/res/values-v21/styles.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
|
||||
</style>
|
||||
</resources>
|
||||
8
libgpsrelaysentinel/src/main/res/values/strings.xml
Normal file
8
libgpsrelaysentinel/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="lib_name">libdebugtemp</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
<string name="text_libraryactivity">LibraryActivity</string>
|
||||
|
||||
</resources>
|
||||
5
libgpsrelaysentinel/src/main/res/values/styles.xml
Normal file
5
libgpsrelaysentinel/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user