From e11099cbd26f959c534a691d68659e141fd5330b Mon Sep 17 00:00:00 2001 From: Zhao Date: Mon, 28 Jul 2025 16:17:45 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AB=98=E5=BE=B7=E5=AE=9A=E4=BD=8D=20?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E6=8C=87=E7=A4=BA=E5=99=A8=20=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- app/build.gradle | 11 +- app/src/main/AndroidManifest.xml | 16 +- .../com/nsgk/ruralWeb/FullscreenActivity.java | 75 +++++-- .../ruralWeb/location/NSAMapLocation.java | 19 +- .../location/NSLastKnownLocation.java | 84 +++++++ .../ruralWeb/location/NSRealtimeLocation.java | 19 +- .../ruralWeb/location/NSSystemLocation.java | 116 ++++------ .../com/nsgk/ruralWeb/sys/NSConstants.java | 28 +++ .../com/nsgk/ruralWeb/sys/NSPreference.java | 3 +- .../nsgk/ruralWeb/ui/SettingsFragment.java | 77 ++++++- .../nsgk/ruralWeb/utils/NSContextUtils.java | 71 ++++-- .../nsgk/ruralWeb/web/NSEnvWindowObject.java | 212 ++++++++++++------ .../res/drawable/indicator_background.xml | 12 + .../main/res/layout/location_indicator.xml | 24 ++ app/src/main/res/values/arrays.xml | 4 +- app/src/main/res/xml/settings_preference.xml | 7 + gradle.properties | 6 +- 18 files changed, 596 insertions(+), 191 deletions(-) create mode 100644 app/src/main/java/com/nsgk/ruralWeb/location/NSLastKnownLocation.java create mode 100644 app/src/main/res/drawable/indicator_background.xml create mode 100644 app/src/main/res/layout/location_indicator.xml diff --git a/README.md b/README.md index 75f08d8..bc103f1 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,13 @@ * 使用Android Studio生成签名包 * 配置```appCopyright=```启动页版权文本, 不要加双引号 * 配置```appVendor=```启动页厂商名称, 不要加双引号 +* 配置```appUpdateUrl=```apk下载更新地址, 不要加双引号 * 生成的apk路径为 `/app/release/app-release.apk` > 使用`gradle`脚本打签名的正式包 * 执行 ```gradlew assembleRelease``` 将使用`gradle.properties`文件里的配置进行打包 -* 如果需要自定义配置(无需修改`gradle.properties`文件), 执行 ```gradlew assembleRelease -PappHomeUrl="首页地址" -PappName="App桌面快捷方式名称(只能使用字符串)" -PappIconKey="图标名称" -PappIconKey="启动页版权文本" -PappCopyright="启动页厂商名称"``` 将使用命令行里的配置进行打包 +* 如果需要自定义配置(无需修改`gradle.properties`文件), 执行 ```gradlew assembleRelease -PappHomeUrl="首页地址" -PappName="App桌面快捷方式名称(只能使用字符串)" -PappIconKey="图标名称" -PappIconKey="启动页版权文本" -PappCopyright="启动页厂商名称" -PappUpdateUrl="apk下载更新地址"``` 将使用命令行里的配置进行打包 * 生成的apk路径为 `/app/build/outputs/apk/release/app-release.apk` > 帮助脚本 diff --git a/app/build.gradle b/app/build.gradle index ce067eb..7c33dd3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { minSdkVersion 24 targetSdkVersion 30 versionCode 1 - versionName "1.0" + versionName "1.0.0.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -25,6 +25,9 @@ android { // App图标 buildConfigField "String", "APP_ICON", "\"${project.properties.appIconKey}\"" + // App更新下载地址 + buildConfigField "String", "APP_UPDATE_URL", "\"${project.properties.appUpdateUrl}\"" + // AndroidManifest.xml占位符 manifestPlaceholders = [ // App名称 @@ -32,7 +35,9 @@ android { // App图标 APP_ICON: "@mipmap/ic_launcher_${project.properties.appIconKey}", // App圆角图标 - APP_ROUND_ICON: "@mipmap/ic_launcher_${project.properties.appIconKey}_round" + APP_ROUND_ICON: "@mipmap/ic_launcher_${project.properties.appIconKey}_round", + // 高德key + AMAP_KEY: "${project.properties.amapKey}", ] } @@ -56,6 +61,7 @@ android { resValue("string", "app_copyright", "\"${project.properties.appCopyright}\"") resValue("string", "app_vendor", "\"${project.properties.appVendor}\"") resValue("string", "app_name2", "\"${project.properties.appName}\"") + resValue("string", "app_update_url", "\"${project.properties.appUpdateUrl}\"") } debug { signingConfig signingConfigs.release @@ -63,6 +69,7 @@ android { resValue("string", "app_copyright", "\"${project.properties.appCopyright}\"") resValue("string", "app_vendor", "\"${project.properties.appVendor}\"") resValue("string", "app_name2", "\"${project.properties.appName}\"") + resValue("string", "app_update_url", "\"${project.properties.appUpdateUrl}\"") } } compileOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 54bf096..b5e001d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,7 +48,7 @@ android:theme="@style/Theme.Nsgk_rural_web"> + android:value="${AMAP_KEY}"/> --> + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/nsgk/ruralWeb/FullscreenActivity.java b/app/src/main/java/com/nsgk/ruralWeb/FullscreenActivity.java index 14be436..ad23702 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/FullscreenActivity.java +++ b/app/src/main/java/com/nsgk/ruralWeb/FullscreenActivity.java @@ -10,6 +10,7 @@ import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.KeyEvent; +import android.view.View; import android.view.ViewGroup; import android.webkit.ConsoleMessage; import android.webkit.GeolocationPermissions; @@ -18,6 +19,7 @@ import android.webkit.WebHistoryItem; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Toast; @@ -54,6 +56,7 @@ public class FullscreenActivity extends AppCompatActivity { private String m_lastUrl; private String m_mainUrl; + private View m_progressIndicator; @SuppressLint("SetJavaScriptEnabled") @Override @@ -167,6 +170,18 @@ public class FullscreenActivity extends AppCompatActivity { mAgentWeb.getJsInterfaceHolder().addJavaObject("_Native_object", envWindowObject); mAgentWeb.getJsInterfaceHolder().addJavaObject("Android", envWindowObject); + // 等待条指示器 + m_progressIndicator = getLayoutInflater().inflate(R.layout.location_indicator, null); + m_progressIndicator.findViewById(R.id.terminate_button).setOnClickListener((View view) -> { + envWindowObject.TerminateLocation(); + }); + m_progressIndicator.setVisibility(View.GONE); + m_progressIndicator.setZ(99); + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + params.addRule(RelativeLayout.CENTER_IN_PARENT); + ((RelativeLayout)findViewById(R.id.ll)).addView(m_progressIndicator, params); + + /* 上边url是各个APP项目的入口地址 事项审批 http://116.255.223.226:82/yinnongLogin 图标 ic_launcher_sxsp 或者 ic_launcher_yhzl 阳光村务(村级事项) http://116.255.223.226:82/sunVillage_info/login 图标 ic_launcher_ygcw @@ -215,16 +230,21 @@ public class FullscreenActivity extends AppCompatActivity { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { -// if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { -// mWebView.goBack(); -// return true; -// } + if (keyCode == KeyEvent.KEYCODE_BACK && HandleBackKeyEvent(1)) { + return true; + } if (mAgentWeb.handleKeyEvent(keyCode, event)) { return true; } return super.onKeyDown(keyCode, event); } + @Override + public void onBackPressed() + { + if(!HandleBackKeyEvent(2)) + super.onBackPressed(); + } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { @@ -250,19 +270,6 @@ public class FullscreenActivity extends AppCompatActivity { } } - @Override - public void onBackPressed() - { - WebView webView = GetWebView(); - if (null != webView && !webView.canGoBack() && !IsInDefaultPage()) { - webView.loadUrl(NSConstants.AppHomeUrl()); - webView.clearHistory(); - //History(); - return; - } - super.onBackPressed(); - } - private NSPreference GetPreference() { if(null == preference) @@ -337,4 +344,38 @@ public class FullscreenActivity extends AppCompatActivity { Log.d(ID_TAG, StrUtil.format("{}: {} {}", i, item.getTitle(), item.getUrl())); } } + + public void SetIndicatorVisible(boolean on) + { + m_progressIndicator.setVisibility(on ? View.VISIBLE : View.GONE); + } + + private boolean HandleBackKeyEvent(int from) + { + if(!IsRecordUrl()) + return false; + WebView webView = GetWebView(); + if(null == webView) + return false; + + boolean inDefaultPage = IsInDefaultPage(); + //System.err.println(m_lastUrl +" -> " + inDefaultPage + " = " + webView.canGoBack()); + if(inDefaultPage) + { + if(from == 1 && !webView.canGoBack()) + { + finish(); + return true; + } + else + return false; + } + if (!webView.canGoBack() && !inDefaultPage) { + webView.loadUrl(NSConstants.AppHomeUrl()); + webView.clearHistory(); + //History(); + return true; + } + return false; + } } \ No newline at end of file diff --git a/app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java b/app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java index 965b2ff..7af0885 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java +++ b/app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java @@ -186,7 +186,7 @@ public class NSAMapLocation implements AMapLocationListener //设置场景模式后最好调用一次stop,再调用start以保证场景模式生效 mLocationClient.stopLocation(); - Log.i(ID_TAG, "定位停止"); + Log.i(ID_TAG, "高德定位停止"); } public void Shutdown() @@ -197,6 +197,7 @@ public class NSAMapLocation implements AMapLocationListener return; } + TerminateRead(); Stop(); mLocationClient.onDestroy(); @@ -205,10 +206,10 @@ public class NSAMapLocation implements AMapLocationListener { m_thread.quit(); m_thread = null; - Log.d(ID_TAG, "内建线程结束"); + Log.d(ID_TAG, "高德定位内建线程结束"); } - Log.i(ID_TAG, "定位销毁"); + Log.i(ID_TAG, "高德定位销毁"); } public void PreInit() @@ -346,8 +347,7 @@ public class NSAMapLocation implements AMapLocationListener @Override public void onLocationChanged(AMapLocation amapLocation) { - Log.d(ID_TAG, "onLocationChanged线程: " + Thread.currentThread().getId()); - System.err.println(amapLocation); + Log.d(ID_TAG, "AMap定位回调线程: " + Thread.currentThread().getId() + " -> " + amapLocation); SetLastLocation(amapLocation); if(null != amapLocation) { @@ -446,6 +446,15 @@ public class NSAMapLocation implements AMapLocationListener return m_lastLocation; } + public void TerminateRead() + { + synchronized(m_lock) + { + Log.i(ID_TAG, "AMap中止定位"); + m_lock.notifyAll(); + } + } + public void CleanLastLocation() { m_lastLocation = null; diff --git a/app/src/main/java/com/nsgk/ruralWeb/location/NSLastKnownLocation.java b/app/src/main/java/com/nsgk/ruralWeb/location/NSLastKnownLocation.java new file mode 100644 index 0000000..a1e35c7 --- /dev/null +++ b/app/src/main/java/com/nsgk/ruralWeb/location/NSLastKnownLocation.java @@ -0,0 +1,84 @@ +package com.nsgk.ruralWeb.location; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.os.Build; +import android.os.CancellationSignal; +import android.util.Log; +import android.widget.Toast; + +import com.nsgk.ruralWeb.sys.NSConstants; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class NSLastKnownLocation +{ + private static final String ID_TAG = NSLastKnownLocation.class.getName(); + + private final Context m_context; + private NSLocationInfo m_lastLocation = null; + + public NSLastKnownLocation(Context context) + { + m_context = context; + } + + @SuppressLint("MissingPermission") + public NSLocationInfo Read(String type) + { + NSLocationInfo loc = null; + try + { + LocationManager lm = (LocationManager) m_context.getSystemService(Context.LOCATION_SERVICE); + + List allProviders = lm.getAllProviders(); + Log.i(ID_TAG, "使用最近所有定位提供器: " + allProviders); + Map map = new HashMap<>(); + for(String provider : allProviders) + { + Location lastKnownLocation = lm.getLastKnownLocation(provider); + if(null == lastKnownLocation) + continue; + NSLocationInfo l = new NSLocationInfo(provider, lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude()); + map.put(provider, l); + } + + Log.i(ID_TAG, "最近定位提供器结果: " + map); + if(null != type && !type.isEmpty() && map.containsKey(type)) + loc = map.get(type); + else if(map.containsKey(LocationManager.GPS_PROVIDER)) + loc = map.get(LocationManager.GPS_PROVIDER); + else if(map.containsKey(LocationManager.NETWORK_PROVIDER)) + loc = map.get(LocationManager.NETWORK_PROVIDER); + else if(map.containsKey(NSConstants.FUSED_PROVIDER)) + loc = map.get(NSConstants.FUSED_PROVIDER); + else if(map.containsKey(LocationManager.PASSIVE_PROVIDER)) + loc = map.get(LocationManager.PASSIVE_PROVIDER); + if(null == loc) + Log.i(ID_TAG, "所有提供器无最近定位"); + else + { + Log.i(ID_TAG, "使用提供器最近定位: " + loc.provider); + m_lastLocation = loc; + } + } + catch(Throwable e) + { + e.printStackTrace(); + } + return loc; + } + + public NSLocationInfo GetLastLocation() + { + return m_lastLocation; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nsgk/ruralWeb/location/NSRealtimeLocation.java b/app/src/main/java/com/nsgk/ruralWeb/location/NSRealtimeLocation.java index a782b46..9ce1c01 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/location/NSRealtimeLocation.java +++ b/app/src/main/java/com/nsgk/ruralWeb/location/NSRealtimeLocation.java @@ -159,7 +159,7 @@ public class NSRealtimeLocation implements LocationListener m_locationManager.removeUpdates(this); m_provider = null; - Log.i(ID_TAG, "定位停止"); + Log.i(ID_TAG, "实时定位停止"); } public void Shutdown() @@ -170,6 +170,7 @@ public class NSRealtimeLocation implements LocationListener return; } + TerminateRead(); Stop(); m_locationManager = null; @@ -177,10 +178,10 @@ public class NSRealtimeLocation implements LocationListener { m_thread.quit(); m_thread = null; - Log.d(ID_TAG, "内建线程结束"); + Log.d(ID_TAG, "实时定位内建线程结束"); } - Log.i(ID_TAG, "定位销毁"); + Log.i(ID_TAG, "实时定位销毁"); } public boolean IsInitialized() @@ -350,8 +351,7 @@ public class NSRealtimeLocation implements LocationListener @Override public void onLocationChanged(@NonNull Location location) { - Log.d(ID_TAG, "onLocationChanged线程: " + Thread.currentThread().getId()); - System.err.println(location); + Log.d(ID_TAG, "系统实时定位线程: " + Thread.currentThread().getId() + " -> " + location); SetLastLocation(location); //if(null != location) { @@ -368,4 +368,13 @@ public class NSRealtimeLocation implements LocationListener } } } + + public void TerminateRead() + { + synchronized(m_lock) + { + Log.i(ID_TAG, "系统实时中止定位"); + m_lock.notifyAll(); + } + } } diff --git a/app/src/main/java/com/nsgk/ruralWeb/location/NSSystemLocation.java b/app/src/main/java/com/nsgk/ruralWeb/location/NSSystemLocation.java index 81f9f1c..8df913f 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/location/NSSystemLocation.java +++ b/app/src/main/java/com/nsgk/ruralWeb/location/NSSystemLocation.java @@ -7,6 +7,7 @@ import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.os.Build; +import android.os.CancellationSignal; import android.util.Log; import android.widget.Toast; @@ -14,92 +15,28 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; public class NSSystemLocation { private static final String ID_TAG = NSSystemLocation.class.getName(); - public static final String FUSED_PROVIDER = "fused"; private final Context m_context; private NSLocationInfo m_lastLocation = null; + private volatile CancellationSignal m_cancellationSignal; + private volatile CompletableFuture m_future; public NSSystemLocation(Context context) { m_context = context; } - public NSLocationInfo GetLocation(String provider) - { - NSLocationInfo loc; - - try - { - loc = GetHighLocation(provider); - if(null == loc) - loc = GetLastLocation(provider); - - if(null != loc) - m_lastLocation = loc; - else - ShowToast("定位失败, 请先开启位置服务", Toast.LENGTH_LONG); - - return loc; - } - catch(Throwable e) - { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - @SuppressLint("MissingPermission") - private NSLocationInfo GetLastLocation(final String type) - { - NSLocationInfo loc = null; - try - { - LocationManager lm = (LocationManager) m_context.getSystemService(Context.LOCATION_SERVICE); - - List allProviders = lm.getAllProviders(); - Log.i(ID_TAG, "使用最近所有定位提供器: " + allProviders); - Map map = new HashMap<>(); - for(String provider : allProviders) - { - Location lastKnownLocation = lm.getLastKnownLocation(provider); - if(null == lastKnownLocation) - continue; - NSLocationInfo l = new NSLocationInfo(provider, lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude()); - map.put(provider, l); - } - - Log.i(ID_TAG, "最近定位提供器结果: " + map); - if(null != type && !type.isEmpty() && map.containsKey(type)) - loc = map.get(type); - else if(map.containsKey(LocationManager.GPS_PROVIDER)) - loc = map.get(LocationManager.GPS_PROVIDER); - else if(map.containsKey(LocationManager.NETWORK_PROVIDER)) - loc = map.get(LocationManager.NETWORK_PROVIDER); - else if(map.containsKey(FUSED_PROVIDER)) - loc = map.get(FUSED_PROVIDER); - else if(map.containsKey(LocationManager.PASSIVE_PROVIDER)) - loc = map.get(LocationManager.PASSIVE_PROVIDER); - if(null == loc) - Log.i(ID_TAG, "所有提供器无最近定位"); - else - Log.i(ID_TAG, "使用提供器最近定位: " + loc.provider); - } - catch(Throwable e) - { - e.printStackTrace(); - } - return loc; - } - @SuppressLint("MissingPermission") - private NSLocationInfo GetHighLocation(String provider) + public NSLocationInfo Read(String provider, int timeout) { if(Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + Log.w(ID_TAG, "获取当前定位请求Android 11+"); return null; } @@ -153,9 +90,16 @@ public class NSSystemLocation return null; } - CompletableFuture future = new CompletableFuture<>(); - lm.getCurrentLocation(provider, null, m_context.getMainExecutor(), future::complete); - Location location = future.get(); + m_cancellationSignal = new CancellationSignal(); + m_future = new CompletableFuture<>(); + lm.getCurrentLocation(provider, m_cancellationSignal, m_context.getMainExecutor(), m_future::complete); + Location location; + if(timeout > 0) + location = m_future.get(timeout, TimeUnit.MILLISECONDS); + else + location = m_future.get(); + m_cancellationSignal = null; + m_future = null; if(null == location) { Log.i(ID_TAG, "无法使用高精度提供器定位"); @@ -163,11 +107,17 @@ public class NSSystemLocation } loc = new NSLocationInfo(provider, location.getLongitude(), location.getLatitude()); Log.i(ID_TAG, "使用高精度提供器获取定位: " + loc); + m_lastLocation = loc; } catch(Throwable e) { e.printStackTrace(); } + finally + { + m_cancellationSignal = null; + m_future = null; + } return loc; } @@ -182,6 +132,28 @@ public class NSSystemLocation })); } + public void TerminateRead() + { + CancellationSignal signal = m_cancellationSignal; + if(null != signal && !signal.isCanceled()) + { + Log.i(ID_TAG, "系统中止定位: 1. 取消定位"); + signal.cancel(); + } + CompletableFuture future = m_future; + if(null != future && !future.isCancelled()) + { + Log.i(ID_TAG, "系统中止定位: 2. 取消等待结果"); + future.cancel(true); + } + } + + public void Shutdown() + { + Log.i(ID_TAG, "销毁系统定位"); + TerminateRead(); + } + public NSLocationInfo GetLastLocation() { return m_lastLocation; diff --git a/app/src/main/java/com/nsgk/ruralWeb/sys/NSConstants.java b/app/src/main/java/com/nsgk/ruralWeb/sys/NSConstants.java index 710b1d6..6e01d87 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/sys/NSConstants.java +++ b/app/src/main/java/com/nsgk/ruralWeb/sys/NSConstants.java @@ -37,16 +37,39 @@ public final class NSConstants return BuildConfig.APP_VENDOR; } + /** + * App图标 + */ public static String AppIcon() { return BuildConfig.APP_ICON; } + /** + * App更新下载地址 + * 可以在 /gradle.properties 里配置 appUpdateUrl=链接地址, 不要携带双引号 + * 也可以在命令行添加 -PappUpdateUrl="链接地址", 双引号可携带也可不携带 + */ + public static String AppUpdateUrl() + { + return BuildConfig.APP_UPDATE_URL; + } + public static boolean IsHttps() { return AppHomeUrl().startsWith("https://"); } + public static boolean IsDebug() + { + return BuildConfig.DEBUG; + } + + public static boolean IsAMapLocationEnabled() + { + return true; + } + // 偏好默认值 public static final String DEFAULT_LOCATION_MODE = NSEnums.LocationMode.REALTIME; public static final int DEFAULT_LOCATION_GAODE_INTERVAL = 1000; @@ -60,5 +83,10 @@ public final class NSConstants public static final boolean DEFAULT_LOGCAT_CONSOLE_OUTPUT = false; public static final int DEFAULT_LOCATION_TIMEOUT = 0; + + public static final String FUSED_PROVIDER = "fused"; + public static final String APK_UPDATE_DOWNLOAD_DIR = "update"; + public static final String APK_UPDATE_DOWNLOAD_FILE = "latest.apk"; + private NSConstants() {} } diff --git a/app/src/main/java/com/nsgk/ruralWeb/sys/NSPreference.java b/app/src/main/java/com/nsgk/ruralWeb/sys/NSPreference.java index 72af1d4..2eb3b0f 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/sys/NSPreference.java +++ b/app/src/main/java/com/nsgk/ruralWeb/sys/NSPreference.java @@ -19,10 +19,11 @@ public final class NSPreference public static final String LAST_ACCESS_URL = "last_access_url"; public static final String COOKIES = "cookies"; public static final String FONT_SCALE = "font_scale"; - public static final String LOGCAT_CONSOLE_OUTPUT = "logcat_console_output"; + public static final String LOGCAT_CONSOLE_OUTPUT = "logcat_console_output"; public static final String LOCATION_TIMEOUT = "location_timeout"; public static final String RESET_SETTINGS = "RESET_SETTINGS"; public static final String VERSION = "VERSION"; + public static final String UPDATE_DOWNLOAD = "UPDATE_DOWNLOAD"; private final Context context; diff --git a/app/src/main/java/com/nsgk/ruralWeb/ui/SettingsFragment.java b/app/src/main/java/com/nsgk/ruralWeb/ui/SettingsFragment.java index 67cb6b2..f3c4cd5 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/ui/SettingsFragment.java +++ b/app/src/main/java/com/nsgk/ruralWeb/ui/SettingsFragment.java @@ -2,8 +2,14 @@ package com.nsgk.ruralWeb.ui; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.provider.Settings; import android.text.Html; import android.util.Log; import android.widget.Toast; @@ -23,10 +29,13 @@ import com.nsgk.ruralWeb.utils.NSContextUtils; import com.nsgk.ruralWeb.utils.NSMisc; import com.nsgk.ruralWeb.utils.NSStr; +import java.io.File; import java.util.Objects; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; public class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { @@ -88,8 +97,17 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer preference = findPreference(NSPreference.VERSION); preference.setOnPreferenceClickListener(this); - preference = findPreference("location_gaode"); - preference.setVisible(false); + preference = findPreference(NSPreference.UPDATE_DOWNLOAD); + preference.setOnPreferenceClickListener(this); + if(StrUtil.isBlank(NSConstants.AppUpdateUrl())) + preference.setVisible(false); + + // 总是隐藏高德的设置 + if(!NSConstants.IsAMapLocationEnabled() || !NSContextUtils.BuildIsDebug(context)) + { + preference = findPreference("location_gaode"); + preference.setVisible(false); + } } private boolean CheckValueIsNumber(Object newValue, Integer min) @@ -164,7 +182,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer break; } case NSPreference.LOCATION_MODE: - if(Objects.equals(NSEnums.LocationMode.GAODE, newValue)) + if(!NSConstants.IsAMapLocationEnabled() && Objects.equals(NSEnums.LocationMode.GAODE, newValue)) { Log.w(ID_TAG, "高德定位被禁用"); return false; @@ -202,10 +220,63 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Prefer case NSPreference.VERSION: OpenAbout(); break; + case NSPreference.UPDATE_DOWNLOAD: + DownloadUpdate(); + //DownloadUpdateExternally(); + break; } return false; } + private void DownloadUpdateExternally() + { + String updateUrl = NSConstants.AppUpdateUrl(); + if(StrUtil.isBlank(updateUrl)) + return; + + Context context = getContext(); + Toast.makeText(context, "正在打开下载地址......", Toast.LENGTH_SHORT).show(); + NSContextUtils.OpenUrlExternally(context, updateUrl); + } + + private void DownloadUpdate() + { + String updateUrl = NSConstants.AppUpdateUrl(); + if(StrUtil.isBlank(updateUrl)) + return; + + Handler handler = new Handler(Looper.myLooper()); + Context context = getContext(); + Log.d(ID_TAG, "下载apk地址: " + updateUrl); + Toast.makeText(context, "开始下载......", Toast.LENGTH_SHORT).show(); + + // 创建文件夹并删除缓存文件 + File externalFilesDir = context.getExternalFilesDir(null); + String dir = externalFilesDir.getAbsolutePath() + File.separator + NSConstants.APK_UPDATE_DOWNLOAD_DIR; + FileUtil.mkdir(dir); + String file = dir + File.separator + NSConstants.APK_UPDATE_DOWNLOAD_FILE; + Log.d(ID_TAG, "删除文件: " + file); + FileUtil.del(file); + + new Thread(() -> { + long bytes = HttpUtil.downloadFile(updateUrl, file); + Log.d(ID_TAG, "下载apk文件: " + FileUtil.readableFileSize(bytes)); + if(bytes > 0) + { + handler.post(() -> { + Toast.makeText(context, "准备安装......", Toast.LENGTH_SHORT).show(); + NSContextUtils.InstallApk(context, file); + }); + } + else + { + handler.post(() -> { + Toast.makeText(context, "下载更新失败", Toast.LENGTH_LONG).show(); + }); + } + }).start(); + } + private void ResetSettings() { NSPreference preference = new NSPreference(getContext()); diff --git a/app/src/main/java/com/nsgk/ruralWeb/utils/NSContextUtils.java b/app/src/main/java/com/nsgk/ruralWeb/utils/NSContextUtils.java index 62be886..de1c308 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/utils/NSContextUtils.java +++ b/app/src/main/java/com/nsgk/ruralWeb/utils/NSContextUtils.java @@ -8,7 +8,15 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; +import android.os.Build; import android.provider.Settings; +import android.widget.Toast; + +import androidx.core.content.FileProvider; + +import com.nsgk.ruralWeb.sys.NSConstants; + +import java.io.File; public final class NSContextUtils { @@ -42,20 +50,6 @@ public final class NSContextUtils return version; } - public static boolean BuildIsDebug(Context context) - { - try - { - ApplicationInfo info = context.getApplicationInfo(); - return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - } - catch (Exception e) - { - e.printStackTrace(); - return false; // default is release - } - } - public static String GetListName(Context context, String value, int keyResource, int nameResource, String... def) { Resources resources = context.getResources(); @@ -75,5 +69,54 @@ public final class NSContextUtils return context.getResources().getString(id, args); } + public static void OpenUrlExternally(Context context, String url) + { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); + context.startActivity(intent); + } + + public static void InstallApk(Context context, String apkFile) + { + File file = new File(apkFile); + if(!file.isFile()) + return; + + String packageName = context.getPackageName(); + Uri apkUri = FileProvider.getUriForFile(context, packageName + ".fileprovider", file); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!context.getPackageManager().canRequestPackageInstalls()) { + Toast.makeText(context, "Android 8以上安装apk请求允许未知来源App", Toast.LENGTH_LONG).show(); + Intent settingsIntent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + packageName)); + context.startActivity(settingsIntent); + } else { + context.startActivity(intent); + } + } else { + context.startActivity(intent); + } + } + + public static boolean BuildIsDebug(Context context) + { + try + { + ApplicationInfo info = context.getApplicationInfo(); + System.err.println(((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) + " -> " + NSConstants.IsDebug()); + return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 || NSConstants.IsDebug(); + } + catch (Exception e) + { + e.printStackTrace(); + return NSConstants.IsDebug(); // default is release + } + } + private NSContextUtils() {} } diff --git a/app/src/main/java/com/nsgk/ruralWeb/web/NSEnvWindowObject.java b/app/src/main/java/com/nsgk/ruralWeb/web/NSEnvWindowObject.java index 65c4afa..a5b214e 100644 --- a/app/src/main/java/com/nsgk/ruralWeb/web/NSEnvWindowObject.java +++ b/app/src/main/java/com/nsgk/ruralWeb/web/NSEnvWindowObject.java @@ -20,6 +20,7 @@ import androidx.core.app.ActivityCompat; import com.nsgk.ruralWeb.FullscreenActivity; import com.nsgk.ruralWeb.R; import com.nsgk.ruralWeb.enums.NSEnums; +import com.nsgk.ruralWeb.location.NSLastKnownLocation; import com.nsgk.ruralWeb.location.NSLocationInfo; import com.nsgk.ruralWeb.location.NSAMapLocation; import com.nsgk.ruralWeb.location.NSRealtimeLocation; @@ -31,41 +32,51 @@ import com.nsgk.ruralWeb.utils.NSContextUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; public class NSEnvWindowObject { private static final String ID_TAG = NSEnvWindowObject.class.getName(); - private static final String FUSED_PROVIDER = "fused"; private final Handler m_handler; private final Context m_context; private final WebView m_webView; - private final NSSystemLocation location; + private final NSSystemLocation m_systemLocation; + private final NSLastKnownLocation m_lastKnownLocation; + private final NSAMapLocation m_amapLocation; + private final NSRealtimeLocation m_realtimeLocation; - private final NSAMapLocation amapLocation; - private final NSRealtimeLocation realtimeLocation; - private final NSPreference preference; + private final NSPreference m_preference; // 最近一次获取到的定位坐标, 如果获取定位失败则返回此值. 可能不需要, 因为PASSIVE_PROVIDER就为最近的定位 - private String lastLocation = null; + private String m_lastLocation = null; + + private static final int LOCATION_STATE_READY = 0; // 准备 + private static final int LOCATION_STATE_PROCESSING = 1; // 进行中 + private static final int LOCATION_STATE_FINISH = 2; // 完成 + private static final int LOCATION_STATE_TERMINATED = 3; // 中止 + + private AtomicInteger m_locationState = new AtomicInteger(LOCATION_STATE_READY); public NSEnvWindowObject(Context context, Handler handler, WebView webView) { m_context = context; m_handler = handler; m_webView = webView; - location = new NSSystemLocation(m_context); - amapLocation = new NSAMapLocation(m_context); - realtimeLocation = new NSRealtimeLocation(m_context); - preference = new NSPreference(m_context); + m_systemLocation = new NSSystemLocation(m_context); + m_lastKnownLocation = new NSLastKnownLocation(m_context); + m_amapLocation = new NSAMapLocation(m_context); + m_realtimeLocation = new NSRealtimeLocation(m_context); + m_preference = new NSPreference(m_context); } public void OnDestroy() { - if(amapLocation.IsInitialized()) - amapLocation.Shutdown(); - if(realtimeLocation.IsInitialized()) - realtimeLocation.Shutdown(); + if(m_amapLocation.IsInitialized()) + m_amapLocation.Shutdown(); + if(m_realtimeLocation.IsInitialized()) + m_realtimeLocation.Shutdown(); + m_systemLocation.Shutdown(); } @JavascriptInterface @@ -76,12 +87,8 @@ public class NSEnvWindowObject private void ShowToast(final String message, int duration) { - RunOnUIThread(new Runnable() { - @Override - public void run() - { - Toast.makeText(m_context, message, duration).show(); - } + RunOnUIThread(() -> { + Toast.makeText(m_context, message, duration).show(); }); } @@ -98,37 +105,44 @@ public class NSEnvWindowObject if(!CheckLocationPermission()) { - return lastLocation; + return m_lastLocation; } + SetLocationState(LOCATION_STATE_READY); + ShowIndicator(); NSLocationInfo loc; String location = CurrentLocationMode(); - String provider = preference.GetString(NSPreference.LOCATION_PROVIDER, NSConstants.DEFAULT_LOCATION_PROVIDER); + String provider = m_preference.GetString(NSPreference.LOCATION_PROVIDER, NSConstants.DEFAULT_LOCATION_PROVIDER); Log.d(ID_TAG, "定位提供器: " + provider); + SetLocationState(LOCATION_STATE_PROCESSING); switch(location) { case NSEnums.LocationMode.GAODE: loc = GetAMapLocation(); - if(null == loc) - loc = GetBuiltInLocation(provider); break; case NSEnums.LocationMode.REALTIME: loc = GetRealtimeLocation(); - if(null == loc) - loc = GetBuiltInLocation(provider); break; case NSEnums.LocationMode.SYSTEM: default: - loc = GetBuiltInLocation(provider); + loc = GetCurrentLocation(provider); break; } + SetLocationState(LOCATION_STATE_FINISH, LOCATION_STATE_PROCESSING); + if(null == loc) + { + if(IsLocationState(LOCATION_STATE_FINISH)) + ShowToast("定位失败, 请先开启位置服务", Toast.LENGTH_LONG); + loc = GetLastKnownLocation(provider); + } + HideIndicator(); return SetLastLocation(loc); } public String CurrentLocationMode() { - return preference.GetString(NSPreference.LOCATION_MODE, NSConstants.DEFAULT_LOCATION_MODE); + return m_preference.GetString(NSPreference.LOCATION_MODE, NSConstants.DEFAULT_LOCATION_MODE); } @JavascriptInterface @@ -140,7 +154,7 @@ public class NSEnvWindowObject @JavascriptInterface public int GetLocationTimeout() { - return preference.GetIntFromString(NSPreference.LOCATION_TIMEOUT, NSConstants.DEFAULT_LOCATION_TIMEOUT); + return m_preference.GetIntFromString(NSPreference.LOCATION_TIMEOUT, NSConstants.DEFAULT_LOCATION_TIMEOUT); } @JavascriptInterface @@ -182,7 +196,7 @@ public class NSEnvWindowObject } } - preference.SetString(NSPreference.LOCATION_MODE, mode); + m_preference.SetString(NSPreference.LOCATION_MODE, mode); res[0] = mode; String name = locationModeList.get(selected[0]); Toast.makeText(m_context, "使用" + name + "定位", Toast.LENGTH_SHORT).show(); @@ -192,7 +206,7 @@ public class NSEnvWindowObject }); builder.setNeutralButton("默认", (DialogInterface dialog, int which) -> { res[0] = NSConstants.DEFAULT_LOCATION_MODE; - preference.SetString(NSPreference.LOCATION_MODE, res[0]); + m_preference.SetString(NSPreference.LOCATION_MODE, res[0]); int choose = locationModeValueList.indexOf(res[0]); String name = locationModeList.get(choose); Toast.makeText(m_context, "使用" + name + "定位", Toast.LENGTH_SHORT).show(); @@ -225,20 +239,21 @@ public class NSEnvWindowObject private String SetLastLocation(NSLocationInfo loc) { if(null != loc) - lastLocation = ReturnLocation(loc); - return lastLocation; + m_lastLocation = ReturnLocation(loc); + return m_lastLocation; } - private NSLocationInfo GetBuiltInLocation(String type) + private NSLocationInfo GetCurrentLocation(String type) { - Log.i(ID_TAG, "使用系统定位"); + Log.i(ID_TAG, "使用系统当前定位"); NSLocationInfo loc = null; try { + int timeout = m_preference.GetIntFromString(NSPreference.LOCATION_TIMEOUT, NSConstants.DEFAULT_LOCATION_TIMEOUT); long start = System.currentTimeMillis(); - loc = location.GetLocation(type); + loc = m_systemLocation.Read(type, timeout); long end = System.currentTimeMillis(); - Log.i(ID_TAG, "系统定位结果: " + loc + ", 耗时=" + (end - start) + "毫秒"); + Log.i(ID_TAG, "系统当前定位结果: " + loc + ", 耗时=" + (end - start) + "毫秒"); } catch(Throwable e) { @@ -247,6 +262,24 @@ public class NSEnvWindowObject return loc; } + private NSLocationInfo GetLastKnownLocation(String type) + { + Log.i(ID_TAG, "使用系统最近定位"); + NSLocationInfo loc; + try + { + long start = System.currentTimeMillis(); + loc = m_lastKnownLocation.Read(type); + long end = System.currentTimeMillis(); + Log.i(ID_TAG, "系统定位最近结果: " + loc + ", 耗时=" + (end - start) + "毫秒"); + } + catch(Throwable e) + { + e.printStackTrace(); + } + return m_lastKnownLocation.GetLastLocation(); + } + private NSLocationInfo GetRealtimeLocation() { Log.i(ID_TAG, "使用系统实时定位"); @@ -254,10 +287,10 @@ public class NSEnvWindowObject try { NSPreference preference = new NSPreference(m_context); - if(!realtimeLocation.IsInitialized()) + if(!m_realtimeLocation.IsInitialized()) { - realtimeLocation.SetOption(NSRealtimeLocation.OPTION_MIN_TIME, preference.GetIntFromString(NSPreference.LOCATION_REALTIME_INTERVAL, NSConstants.DEFAULT_LOCATION_REALTIME_INTERVAL)); - realtimeLocation.SetOption(NSRealtimeLocation.OPTION_MIN_DISTANCE, preference.GetIntFromString(NSPreference.LOCATION_REALTIME_DISTANCE, NSConstants.DEFAULT_LOCATION_REALTIME_DISTANCE)); + m_realtimeLocation.SetOption(NSRealtimeLocation.OPTION_MIN_TIME, preference.GetIntFromString(NSPreference.LOCATION_REALTIME_INTERVAL, NSConstants.DEFAULT_LOCATION_REALTIME_INTERVAL)); + m_realtimeLocation.SetOption(NSRealtimeLocation.OPTION_MIN_DISTANCE, preference.GetIntFromString(NSPreference.LOCATION_REALTIME_DISTANCE, NSConstants.DEFAULT_LOCATION_REALTIME_DISTANCE)); int flag = NSRealtimeLocation.DEFAULT_FLAG | NSRealtimeLocation.FLAG_BUILTIN_THREAD; String provider = preference.GetString(NSPreference.LOCATION_PROVIDER, NSConstants.DEFAULT_LOCATION_PROVIDER); if(LocationManager.GPS_PROVIDER.equals(provider)) @@ -265,12 +298,12 @@ public class NSEnvWindowObject flag &= ~NSRealtimeLocation.FLAG_PRIORITY_NETWORK; flag |= NSRealtimeLocation.FLAG_PRIORITY_GPS; } - realtimeLocation.Init(flag); + m_realtimeLocation.Init(flag); } long start = System.currentTimeMillis(); int count = preference.GetIntFromString(NSPreference.LOCATION_REALTIME_READ_COUNT, NSConstants.DEFAULT_LOCATION_REALTIME_READ_COUNT); int timeout = preference.GetIntFromString(NSPreference.LOCATION_TIMEOUT, NSConstants.DEFAULT_LOCATION_TIMEOUT); - loc = realtimeLocation.Read(count, timeout); + loc = m_realtimeLocation.Read(count, timeout); long end = System.currentTimeMillis(); Log.i(ID_TAG, "系统实时定位结果: " + loc + ", 耗时=" + (end - start) + "毫秒"); } @@ -288,15 +321,15 @@ public class NSEnvWindowObject try { NSPreference preference = new NSPreference(m_context); - if(!amapLocation.IsInitialized()) + if(!m_amapLocation.IsInitialized()) { - amapLocation.SetOption(NSAMapLocation.OPTION_INTERVAL, preference.GetIntFromString(NSPreference.LOCATION_GAODE_INTERVAL, NSConstants.DEFAULT_LOCATION_GAODE_INTERVAL)); - amapLocation.Init(NSAMapLocation.DEFAULT_FLAG | NSAMapLocation.FLAG_BUILTIN_THREAD); + m_amapLocation.SetOption(NSAMapLocation.OPTION_INTERVAL, preference.GetIntFromString(NSPreference.LOCATION_GAODE_INTERVAL, NSConstants.DEFAULT_LOCATION_GAODE_INTERVAL)); + m_amapLocation.Init(NSAMapLocation.DEFAULT_FLAG | NSAMapLocation.FLAG_BUILTIN_THREAD); } long start = System.currentTimeMillis(); int count = preference.GetIntFromString(NSPreference.LOCATION_GAODE_READ_COUNT, NSConstants.DEFAULT_LOCATION_GAODE_READ_COUNT); int timeout = preference.GetIntFromString(NSPreference.LOCATION_TIMEOUT, NSConstants.DEFAULT_LOCATION_TIMEOUT); - loc = amapLocation.Read(count, timeout); + loc = m_amapLocation.Read(count, timeout); long end = System.currentTimeMillis(); Log.i(ID_TAG, "高德定位结果: " + loc + ", 耗时=" + (end - start) + "毫秒"); } @@ -351,19 +384,15 @@ public class NSEnvWindowObject sb.append(", "); } final String arg = sb.toString(); - RunOnUIThread(new Runnable() { - @Override - public void run() - { - String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");"; - Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg)); - m_webView.evaluateJavascript(script, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - Log.e(ID_TAG, String.format("js函数 %s 返回: %s", func, value)); - } - }); - } + RunOnUIThread(() -> { + String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");"; + Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg)); + m_webView.evaluateJavascript(script, new ValueCallback() { + @Override + public void onReceiveValue(String value) { + Log.e(ID_TAG, String.format("js函数 %s 返回: %s", func, value)); + } + }); }); } @@ -377,14 +406,63 @@ public class NSEnvWindowObject sb.append(", "); } final String arg = sb.toString(); - RunOnUIThread(new Runnable() { - @Override - public void run() { - Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg)); - String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");"; - Log.e(ID_TAG, script); - m_webView.loadUrl(script, null); - } + RunOnUIThread(() -> { + Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg)); + String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");"; + Log.e(ID_TAG, script); + m_webView.loadUrl(script, null); + }); + } + + protected void ShowIndicator() + { + RunOnUIThread(() -> { + ((FullscreenActivity)(m_context)).SetIndicatorVisible(true); }); } + + protected void HideIndicator() + { + RunOnUIThread(() -> { + ((FullscreenActivity)(m_context)).SetIndicatorVisible(false); + }); + } + + public void TerminateLocation() + { + if(!IsLocationState(LOCATION_STATE_PROCESSING)) + return; + SetLocationState(LOCATION_STATE_TERMINATED, LOCATION_STATE_PROCESSING); + String location = CurrentLocationMode(); + Log.i(ID_TAG, "中止定位: " + location); + switch(location) + { + case NSEnums.LocationMode.GAODE: + m_amapLocation.TerminateRead(); + break; + case NSEnums.LocationMode.REALTIME: + m_realtimeLocation.TerminateRead(); + break; + case NSEnums.LocationMode.SYSTEM: + m_systemLocation.TerminateRead(); + break; + } + + HideIndicator(); + } + + private void SetLocationState(int st) + { + m_locationState.set(st); + } + + private void SetLocationState(int st, int cur) + { + m_locationState.compareAndSet(cur, st); + } + + private boolean IsLocationState(int st) + { + return m_locationState.get() == st; + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/indicator_background.xml b/app/src/main/res/drawable/indicator_background.xml new file mode 100644 index 0000000..825c101 --- /dev/null +++ b/app/src/main/res/drawable/indicator_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/src/main/res/layout/location_indicator.xml b/app/src/main/res/layout/location_indicator.xml new file mode 100644 index 0000000..2628d40 --- /dev/null +++ b/app/src/main/res/layout/location_indicator.xml @@ -0,0 +1,24 @@ + + + + + +