Skip to content

Commit a9c60ec

Browse files
authored
Merge pull request #12 from SimpleAppProjects/develop
v5.8.4
2 parents aa75264 + b7c686b commit a9c60ec

File tree

47 files changed

+861
-1078
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+861
-1078
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
minSdkVersion rootProject.minSdkVersion
1515
targetSdkVersion rootProject.targetSdkVersion
1616
// NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code (Android: 00, WearOS: 01)
17-
versionCode 335830000
18-
versionName "5.8.3"
17+
versionCode 335840000
18+
versionName "5.8.4"
1919

2020
vectorDrawables.useSupportLibrary true
2121
}

app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,7 @@ class SettingsFragment : BaseSettingsFragment(),
814814
settingsManager.setAPIKey(provider, key)
815815
settingsManager.setAPI(provider)
816816
settingsManager.setKeyVerified(provider, true)
817+
settingsManager.setPersonalKey(true)
817818

818819
updateKeySummary()
819820

app/src/main/java/com/thewizrd/simpleweather/setup/SetupProviderFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class SetupProviderFragment : CustomPreferenceFragmentCompat(), StepperFragment
254254
settingsManager.setAPIKey(provider, key)
255255
settingsManager.setAPI(provider)
256256
settingsManager.setKeyVerified(provider, true)
257+
settingsManager.setPersonalKey(true)
257258

258259
updateKeySummary()
259260

app/src/main/java/com/thewizrd/simpleweather/viewmodels/WeatherNowViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ class WeatherNowViewModel(app: Application) : AndroidViewModel(app) {
231231
when (result) {
232232
is WeatherResult.Error -> {
233233
viewModelState.update { state ->
234-
if (state.locationData?.countryCode?.let { !wm.isRegionSupported(it) } == true) {
234+
if (state.locationData?.let { !wm.isRegionSupported(it) } == true) {
235235
Logger.writeLine(
236236
Log.WARN,
237237
"Location: %s; countryCode: %s",
@@ -290,7 +290,7 @@ class WeatherNowViewModel(app: Application) : AndroidViewModel(app) {
290290
val weatherData = result.data.toUiModel()
291291

292292
viewModelState.update { state ->
293-
if (state.locationData?.countryCode?.let { !wm.isRegionSupported(it) } == true) {
293+
if (state.locationData?.let { !wm.isRegionSupported(it) } == true) {
294294
Logger.writeLine(
295295
Log.WARN,
296296
"Location: %s; countryCode: %s",

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ buildscript {
2828
preference_version = '1.2.1'
2929
recyclerview_version = '1.3.1'
3030
room_version = '2.5.2'
31-
coresplash_version = '1.0.0'
31+
coresplash_version = '1.0.1'
3232
work_version = '2.8.1'
3333

3434
test_core_version = '1.5.0'

common/src/fullgms/java/com/thewizrd/common/location/LocationProvider.kt

Lines changed: 142 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ package com.thewizrd.common.location
33
import android.annotation.SuppressLint
44
import android.app.Activity
55
import android.content.Context
6-
import android.location.Criteria
76
import android.location.Location
87
import android.location.LocationManager
8+
import android.os.Build
99
import android.util.Log
1010
import androidx.core.location.LocationManagerCompat
1111
import androidx.core.os.CancellationSignal
1212
import com.google.android.gms.location.FusedLocationProviderClient
13-
import com.google.android.gms.location.LocationRequest
1413
import com.google.android.gms.location.LocationServices
14+
import com.google.android.gms.location.Priority
1515
import com.google.android.gms.tasks.CancellationTokenSource
16+
import com.google.android.gms.tasks.Task
17+
import com.google.android.gms.tasks.Tasks
18+
import com.google.android.gms.wearable.Wearable
1619
import com.thewizrd.common.R
1720
import com.thewizrd.common.helpers.locationPermissionEnabled
1821
import com.thewizrd.common.utils.ErrorMessage
@@ -22,6 +25,7 @@ import com.thewizrd.shared_resources.exceptions.WeatherException
2225
import com.thewizrd.shared_resources.locationdata.LocationData
2326
import com.thewizrd.shared_resources.locationdata.toLocation
2427
import com.thewizrd.shared_resources.locationdata.toLocationData
28+
import com.thewizrd.shared_resources.utils.ContextUtils.isPhone
2529
import com.thewizrd.shared_resources.utils.ConversionMethods
2630
import com.thewizrd.shared_resources.utils.Logger
2731
import com.thewizrd.weather_api.weatherModule
@@ -65,16 +69,12 @@ class LocationProvider {
6569
suspend fun getLastLocation(): Location? {
6670
if (!checkPermissions()) return null
6771

68-
if (isGMSAvailable) {
72+
val isFusedLocationAvailable = canUseFusedLocation().await()
73+
74+
if (isFusedLocationAvailable) {
6975
return mFusedLocationProviderClient.lastLocation.await()
7076
} else {
71-
val locCriteria = Criteria().apply {
72-
accuracy = Criteria.ACCURACY_COARSE
73-
isCostAllowed = false
74-
powerRequirement = Criteria.POWER_LOW
75-
}
76-
77-
val provider = mLocationMgr.getBestProvider(locCriteria, true) ?: return null
77+
val provider = getBestProvider() ?: return null
7878
return mLocationMgr.getLastKnownLocation(provider)
7979
}
8080
}
@@ -89,74 +89,75 @@ class LocationProvider {
8989
return@suspendCancellableCoroutine
9090
}
9191

92-
if (isGMSAvailable) {
93-
val cts = CancellationTokenSource()
92+
canUseFusedLocation()
93+
.continueWith { task ->
94+
if (!continuation.isActive) return@continueWith
9495

95-
continuation.invokeOnCancellation {
96-
cts.cancel()
97-
}
96+
val isFusedLocationAvailable = task.result
9897

99-
mFusedLocationProviderClient.getCurrentLocation(
100-
LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY,
101-
cts.token
102-
).addOnCompleteListener {
103-
if (it.isSuccessful) {
104-
Logger.writeLine(Log.INFO, "$TAG: Location update received...")
98+
if (isFusedLocationAvailable) {
99+
val cts = CancellationTokenSource()
105100

106-
if (continuation.isActive) {
107-
continuation.resume(it.result)
108-
}
109-
} else {
110-
it.exception?.let { ex ->
111-
Logger.writeLine(Log.INFO, ex, "$TAG: Error retrieving location...")
101+
continuation.invokeOnCancellation {
102+
cts.cancel()
112103
}
113104

114-
if (continuation.isActive) {
115-
continuation.resume(null)
105+
mFusedLocationProviderClient.getCurrentLocation(
106+
Priority.PRIORITY_BALANCED_POWER_ACCURACY,
107+
cts.token
108+
).addOnCompleteListener {
109+
if (it.isSuccessful) {
110+
Logger.writeLine(Log.INFO, "$TAG: Location update received...")
111+
112+
if (continuation.isActive) {
113+
continuation.resume(it.result)
114+
}
115+
} else {
116+
it.exception?.let { ex ->
117+
Logger.writeLine(Log.INFO, ex, "$TAG: Error retrieving location...")
118+
}
119+
120+
if (continuation.isActive) {
121+
continuation.resume(null)
122+
}
123+
}
116124
}
117-
}
118-
}
119-
} else {
120-
val locCriteria = Criteria().apply {
121-
accuracy = Criteria.ACCURACY_COARSE
122-
isCostAllowed = false
123-
powerRequirement = Criteria.POWER_LOW
124-
}
125-
126-
val cancelSignal = CancellationSignal()
125+
} else {
126+
val cancelSignal = CancellationSignal()
127127

128-
continuation.invokeOnCancellation {
129-
cancelSignal.cancel()
130-
}
128+
continuation.invokeOnCancellation {
129+
cancelSignal.cancel()
130+
}
131131

132-
val provider = mLocationMgr.getBestProvider(locCriteria, true)
132+
val provider = getBestProvider()
133133

134-
if (provider == null) {
135-
if (continuation.isActive) {
136-
continuation.resume(null)
137-
}
138-
return@suspendCancellableCoroutine
139-
}
134+
if (provider == null) {
135+
if (continuation.isActive) {
136+
continuation.resume(null)
137+
}
138+
return@continueWith
139+
}
140140

141-
runCatching {
142-
LocationManagerCompat.getCurrentLocation(
143-
mLocationMgr,
144-
provider,
145-
cancelSignal,
146-
Executors.newSingleThreadExecutor()
147-
) {
148-
Logger.writeLine(Log.INFO, "$TAG: Location update received...")
149-
if (continuation.isActive) {
150-
continuation.resume(it)
141+
runCatching {
142+
LocationManagerCompat.getCurrentLocation(
143+
mLocationMgr,
144+
provider,
145+
cancelSignal,
146+
Executors.newSingleThreadExecutor()
147+
) {
148+
Logger.writeLine(Log.INFO, "$TAG: Location update received...")
149+
if (continuation.isActive) {
150+
continuation.resume(it)
151+
}
152+
}
153+
}.onFailure {
154+
Logger.writeLine(Log.INFO, it, "$TAG: Error retrieving location...")
155+
if (continuation.isActive) {
156+
continuation.resume(null)
157+
}
151158
}
152159
}
153-
}.onFailure {
154-
Logger.writeLine(Log.INFO, it, "$TAG: Error retrieving location...")
155-
if (continuation.isActive) {
156-
continuation.resume(null)
157-
}
158160
}
159-
}
160161
}
161162

162163
suspend fun getLatestLocationData(previousLocation: LocationData? = null): LocationResult {
@@ -236,4 +237,80 @@ class LocationProvider {
236237

237238
return LocationResult.NotChanged(previousLocation, false)
238239
}
240+
241+
private fun getBestProvider(): String? {
242+
val enabledProviders = mLocationMgr.getProviders(true)
243+
244+
if (enabledProviders.isNotEmpty()) {
245+
return if (mContext.isPhone() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && enabledProviders.contains(
246+
LocationManager.FUSED_PROVIDER
247+
)
248+
) {
249+
LocationManager.FUSED_PROVIDER
250+
} else if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) {
251+
LocationManager.GPS_PROVIDER
252+
} else if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) {
253+
LocationManager.NETWORK_PROVIDER
254+
} else if (enabledProviders.contains(LocationManager.PASSIVE_PROVIDER)) {
255+
LocationManager.PASSIVE_PROVIDER
256+
} else {
257+
enabledProviders.first()
258+
}
259+
}
260+
261+
return null
262+
}
263+
264+
/**
265+
* On non-wearables: Check if Google Play Services are available. If so, return [com.google.android.gms.location.LocationAvailability.isLocationAvailable]
266+
*
267+
* On wearables: Check if Google Play Services are available. If so, check if any paired phone is available and nearby.
268+
* If so, confirm fused location availability [com.google.android.gms.location.LocationAvailability.isLocationAvailable]
269+
*
270+
* @see [FusedLocationProviderClient.getLocationAvailability]
271+
* @see [com.google.android.gms.wearable.NodeClient.getConnectedNodes]
272+
* @return true if we can use fused location provider
273+
*/
274+
private fun canUseFusedLocation(): Task<Boolean> {
275+
return Tasks.forResult(isGMSAvailable)
276+
.continueWithTask {
277+
val isGMSAvailable = it.result
278+
279+
if (isGMSAvailable) {
280+
if (!mContext.isPhone()) {
281+
// Wearables: FusedLocationProvider will likely not be of use if phone is not connected nearby
282+
// Verify phone status
283+
Wearable.getNodeClient(mContext)
284+
.connectedNodes
285+
.continueWithTask { nodesTask ->
286+
if (it.isSuccessful) {
287+
val nodes = nodesTask.result
288+
val isNearbyNodes = nodes.any { n -> n.isNearby }
289+
if (isNearbyNodes) {
290+
isFusedLocationAvailable()
291+
} else {
292+
Tasks.forResult(false)
293+
}
294+
} else {
295+
Tasks.forResult(false)
296+
}
297+
}
298+
} else {
299+
isFusedLocationAvailable()
300+
}
301+
} else {
302+
Tasks.forResult(false)
303+
}
304+
}
305+
}
306+
307+
private fun isFusedLocationAvailable(): Task<Boolean> {
308+
return mFusedLocationProviderClient.locationAvailability.continueWith { avail ->
309+
if (avail.isSuccessful) {
310+
avail.result.isLocationAvailable
311+
} else {
312+
false
313+
}
314+
}
315+
}
239316
}

0 commit comments

Comments
 (0)