diff --git a/app/src/main/ic_launcher-114x114.png b/app/src/main/ic_launcher-114x114.png new file mode 100644 index 000000000..f4ac1da36 Binary files /dev/null and b/app/src/main/ic_launcher-114x114.png differ diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index a2d36be98..dbc81456b 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -334,26 +334,20 @@ class MainActivity : AppCompatActivity(), Logging, private fun askToRate() { exceptionReporter { // Got one IllegalArgumentException from inside this lib, but we don't want to crash our app because of bugs in this optional feature - AppRate.with(this) + val hasGooglePlay = GoogleApiAvailability.getInstance() + .isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING + + val rater = AppRate.with(this) .setInstallDays(10.toByte()) // default is 10, 0 means install day, 10 means app is launched 10 or more days later than installation .setLaunchTimes(10.toByte()) // default is 10, 3 means app is launched 3 or more times .setRemindInterval(1.toByte()) // default is 1, 1 means app is launched 1 or more days after neutral button clicked .setRemindLaunchesNumber(1.toByte()) // default is 0, 1 means app is launched 1 or more times after neutral button clicked - .monitor() // Monitors the app launch times + .setStoreType(if (hasGooglePlay) StoreType.GOOGLEPLAY else StoreType.AMAZON) + + rater.monitor() // Monitors the app launch times // Only ask to rate if the user has a suitable store - if (AppRate.with(this).storeType == StoreType.GOOGLEPLAY) { // Checks that current app store type from library options is StoreType.GOOGLEPLAY - if (GoogleApiAvailability.getInstance() - .isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING - ) { // Checks that Google Play is available - AppRate.showRateDialogIfMeetsConditions(this) // Shows the Rate Dialog when conditions are met - - // Force the dialog - for testing - // AppRate.with(this).showRateDialog(this) - } - } else { - AppRate.showRateDialogIfMeetsConditions(this); // Shows the Rate Dialog when conditions are met - } + AppRate.showRateDialogIfMeetsConditions(this); // Shows the Rate Dialog when conditions are met } } diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index ed94684bb..819f9b592 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -22,6 +22,7 @@ import com.geeksville.analytics.DataPair import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.android.ServiceClient +import com.geeksville.android.isGooglePlayAvailable import com.geeksville.concurrent.handledLaunch import com.geeksville.mesh.* import com.geeksville.mesh.MeshProtos.MeshPacket @@ -242,7 +243,8 @@ class MeshService : Service(), Logging { @SuppressLint("MissingPermission") @UiThread private fun startLocationRequests() { - if (fusedLocationClient == null) { + // FIXME - currently we don't support location reading without google play + if (fusedLocationClient == null && isGooglePlayAvailable(this)) { GeeksvilleApplication.analytics.track("location_start") // Figure out how many users needed to use the phone GPS val request = LocationRequest.create().apply { diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index e5c158f85..c96cd66a3 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -30,6 +30,7 @@ import androidx.lifecycle.Observer import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.android.hideKeyboard +import com.geeksville.android.isGooglePlayAvailable import com.geeksville.concurrent.handledLaunch import com.geeksville.mesh.MainActivity import com.geeksville.mesh.R @@ -687,8 +688,9 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { // To skip filtering based on name and supported feature flags (UUIDs), // don't include calls to setNamePattern() and addServiceUuid(), // respectively. This example uses Bluetooth. + // We only look for Mesh (rather than the full name) because NRF52 uses a very short name val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() - .setNamePattern(Pattern.compile("Meshtastic_.*")) + .setNamePattern(Pattern.compile("Mesh.*")) // .addServiceUuid(ParcelUuid(RadioInterfaceService.BTM_SERVICE_UUID), null) .build() @@ -768,45 +770,48 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { * If the user has not turned on location access throw up a toast warning */ private fun checkLocationEnabled() { - // We do this painful process because LocationManager.isEnabled is only SDK28 or latet - val builder = LocationSettingsRequest.Builder() - builder.setNeedBle(true) + // If they don't have google play FIXME for now we don't check for location access + if (isGooglePlayAvailable(requireContext())) { + // We do this painful process because LocationManager.isEnabled is only SDK28 or latet + val builder = LocationSettingsRequest.Builder() + builder.setNeedBle(true) - val request = LocationRequest.create().apply { - priority = LocationRequest.PRIORITY_HIGH_ACCURACY - } - builder.addLocationRequest(request) // Make sure we are granted high accuracy permission + val request = LocationRequest.create().apply { + priority = LocationRequest.PRIORITY_HIGH_ACCURACY + } + builder.addLocationRequest(request) // Make sure we are granted high accuracy permission - val locationSettingsResponse = LocationServices.getSettingsClient(requireActivity()) - .checkLocationSettings(builder.build()) + val locationSettingsResponse = LocationServices.getSettingsClient(requireActivity()) + .checkLocationSettings(builder.build()) - locationSettingsResponse.addOnSuccessListener { - debug("We have location access") - } + locationSettingsResponse.addOnSuccessListener { + debug("We have location access") + } - locationSettingsResponse.addOnFailureListener { exception -> - errormsg("Failed to get location access") - // We always show the toast regardless of what type of exception we receive. Because even non - // resolvable api exceptions mean user still needs to fix something. - - ///if (exception is ResolvableApiException) { + locationSettingsResponse.addOnFailureListener { exception -> + errormsg("Failed to get location access") + // We always show the toast regardless of what type of exception we receive. Because even non + // resolvable api exceptions mean user still needs to fix something. - // Location settings are not satisfied, but this can be fixed - // by showing the user a dialog. + ///if (exception is ResolvableApiException) { - // Show the dialog by calling startResolutionForResult(), - // and check the result in onActivityResult(). - // exception.startResolutionForResult(this@MainActivity, REQUEST_CHECK_SETTINGS) + // Location settings are not satisfied, but this can be fixed + // by showing the user a dialog. - // For now just punt and show a dialog - Toast.makeText( - requireContext(), - getString(R.string.location_disabled_warning), - Toast.LENGTH_SHORT - ).show() + // Show the dialog by calling startResolutionForResult(), + // and check the result in onActivityResult(). + // exception.startResolutionForResult(this@MainActivity, REQUEST_CHECK_SETTINGS) - //} else - // Exceptions.report(exception) + // For now just punt and show a dialog + Toast.makeText( + requireContext(), + getString(R.string.location_disabled_warning), + Toast.LENGTH_SHORT + ).show() + + //} else + // Exceptions.report(exception) + } } } diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 324354353..cd8c689a2 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -3,40 +3,40 @@ Mesh网络 设置 频道名称 - 频道选项 + 频道设置 分享 QR码 未设置 连接状态 应用图标 - 未知用户名 + 未知用户 用户头像 在吗?我找到了快递,它就在一只大老虎旁边,我好害怕😨! 在此发送信息 - Mesh设备未与此手机配对,请配对设备并设置好您的用户名.\n\n此开源应用程序正在进行alpha测试,如果您发现问题,请在我们的网站中发布.\n\n更多信息,请访问此网页 - www.meshtastic.org. + 设备未配对,请配对设备并设置好用户名.\n\n此开源应用为测试版,若您发现任何问题可以在下面的网站中发布.\n\n更多信息,请访问此网页 - www.meshtastic.org. 用户名未设置 用户名 - 匿名使用情况统计信息和崩溃报告. + 匿名上传崩溃报告. Mesh设备扫描中... + Meshtastic_ac23 + Meshtastic_1267 此应用程序需要蓝牙权限.请在Android设置中授予权限. - 错误:此应用需要蓝牙 + 未开启蓝牙 开始配对 配对失败 用于连接Mesh网络的URL 接受 取消 修改频道 - 您确定要修改通信频道吗?这将会使你与其他节点断开通信. + 您确定要修改通信频道?这将会使你与其他节点断开通信. 收到新的频道URL 您是否要切换到\'%s\'频道? - 您已禁用了分析功能,但是我们的地图提供商(mapbox)要求对其进行分析\'free\' 因此,这将会关闭地图视图.\n\n - 如果您想看地图, 你将\'需要在设置中打开分析功能(此外,暂时可能需要强制重新启动应用)\n\n - 如果您想切换到其他地图提供商,请在meshtastic.discourse.group中发布 + 您已禁用了分析功能,但是我们的地图提供商(mapbox)要求对其进行分析\'free\' 因此,这将会关闭地图视图.\n\n如果您想看地图, 你将\'需要在“设置”中打开匿名统计(同时你需要重启应用)\n\n如果您想切换到其他地图类形,请在meshtastic.discourse.group中发布 缺少必需的权限,Mesh网络将无法正常工作,请在应用程序设置中启用. - LoRa模块正处于休眠之中,您暂时无法更改频道 + 模块正处于休眠之中,无法更改频道 反馈BUG 反馈一个BUG - 您确定要报告错误吗?报告后,请发布在meshtastic.discourse.group中,以便我们将您的报告与您找到的内容进行匹配. + 您确定要报告错误吗?报告后,请发布在网站中,以便将您的报告与您找到的内容进行匹配. 报告 选择LoRa模块 您目前已与LoRa模块配对%s @@ -45,5 +45,27 @@ 请在Android设置中配对设备. 配对成功,服务以启动 配对失败,请再次选择 - 位置访问已禁用,将无法为Mesh设备提供位置. + 位置访问已被禁用,这将无法为设备提供位置服务. + 分享 + 已断开连接 + 设备休眠中 + 连接状态:%s到%s设备在线 + 节点列表 + 更新设备固件 + 已连接设备 + 手机已连接到 (%s) + 未连接,请选择设备 + 已连接,设备休眠中 + 更新到%s + 应用程序版本过旧 + 您需要在Google Play商店(或Github)上更新此应用程序,现在您无法与这台Mesh设备通信. + 无选择(默认) + 短距离(传输快速) + 中等范围(传输较快) + 较大范围(传输较慢) + 超长距离(传输缓慢) + 无法识别 + Mesh服务通知 + 您需要在设置中启用位置服务 + 关于 \ No newline at end of file diff --git a/geeksville-androidlib b/geeksville-androidlib index ab381a83f..cfe31d66e 160000 --- a/geeksville-androidlib +++ b/geeksville-androidlib @@ -1 +1 @@ -Subproject commit ab381a83f5380358fa8412a58635e390c3729192 +Subproject commit cfe31d66e4de324fa91a2978a76ffcfba5e01085 diff --git a/images/amazon-badge.png b/images/amazon-badge.png new file mode 100644 index 000000000..6ec998b8e Binary files /dev/null and b/images/amazon-badge.png differ