Skip to content

Commit

Permalink
Fixed requirements for location services check. (#748)
Browse files Browse the repository at this point in the history
Apparently on >= API 29 Android will require location to be turned on irregardless of the target SDK for the application to return scan results. Prior to API 29 it was a common workaround to use target SDK of 21 so the user will not be prompted to give location permissions and no need for location being turned on by the user to scan for BLE peripherals.
  • Loading branch information
dariuszseweryn authored May 1, 2021
1 parent 8acb6a0 commit 202b9ba
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.polidea.rxandroidble2.internal.util;

import android.os.Build;

import com.polidea.rxandroidble2.ClientComponent;

import bleshadow.javax.inject.Inject;
Expand All @@ -13,17 +11,20 @@ public class LocationServicesStatusApi23 implements LocationServicesStatus {
private final CheckerLocationPermission checkerLocationPermission;
private final boolean isAndroidWear;
private final int targetSdk;
private final int deviceSdk;

@Inject
LocationServicesStatusApi23(
CheckerLocationProvider checkerLocationProvider,
CheckerLocationPermission checkerLocationPermission,
@Named(ClientComponent.PlatformConstants.INT_TARGET_SDK) int targetSdk,
@Named(ClientComponent.PlatformConstants.INT_DEVICE_SDK) int deviceSdk,
@Named(ClientComponent.PlatformConstants.BOOL_IS_ANDROID_WEAR) boolean isAndroidWear
) {
this.checkerLocationProvider = checkerLocationProvider;
this.checkerLocationPermission = checkerLocationPermission;
this.targetSdk = targetSdk;
this.deviceSdk = deviceSdk;
this.isAndroidWear = isAndroidWear;
}

Expand All @@ -39,10 +40,16 @@ public boolean isLocationProviderOk() {
* A function that returns true if the location services may be needed to be turned ON. Since there are no official guidelines
* for Android Wear check is disabled.
*
* @see <a href="https://code.google.com/p/android/issues/detail?id=189090">Google Groups Discussion</a>
* @return true if Location Services need to be turned ON
* @see <a href="https://code.google.com/p/android/issues/detail?id=189090">Google Groups Discussion</a>
*/
private boolean isLocationProviderEnabledRequired() {
return !isAndroidWear && targetSdk >= Build.VERSION_CODES.M;
return !isAndroidWear && (
// Apparently since device API 29 target SDK is not honored and location services need to be
// turned on for the app to get scan results.
// Based on issue https://github.com/Polidea/RxAndroidBle/issues/742
deviceSdk >= 29 /* Build.VERSION_CODES.Q */
|| targetSdk >= 23 /* Build.VERSION_CODES.M */
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,24 @@ class LocationServicesStatusApi23Test extends Specification {
def mockCheckerLocationProvider = Mock CheckerLocationProvider
def mockCheckerLocationPermission = Mock CheckerLocationPermission
int mockApplicationTargetSdk
int mockApplicationDeviceSdk
boolean mockIsAndroidWear
LocationServicesStatusApi23 objectUnderTest

private prepareObjectUnderTest() {
objectUnderTest = new LocationServicesStatusApi23(mockCheckerLocationProvider, mockCheckerLocationPermission, mockApplicationTargetSdk, mockIsAndroidWear)
objectUnderTest = new LocationServicesStatusApi23(mockCheckerLocationProvider, mockCheckerLocationPermission, mockApplicationTargetSdk, mockApplicationDeviceSdk, mockIsAndroidWear)
}

// API 18 is the first version with official AOSP BLE, API 21 is the last w/o need of location
@Shared
private def sdkVersionsPreM = [
Build.VERSION_CODES.JELLY_BEAN_MR2,
Build.VERSION_CODES.KITKAT,
Build.VERSION_CODES.KITKAT_WATCH,
Build.VERSION_CODES.LOLLIPOP,
Build.VERSION_CODES.LOLLIPOP_MR1,
]
private def targetSdkVersionsWithoutLocationNeed = [Build.VERSION_CODES.JELLY_BEAN_MR2, Build.VERSION_CODES.LOLLIPOP_MR1]

// API 22 is the first that needs location, API 28 is the last that deviceSdk that does not need location if targetSdk < API 22, API 29 needs location regardless of targetSdk
@Shared
private def sdkVersionsPostM = [
Build.VERSION_CODES.M,
Build.VERSION_CODES.N,
Build.VERSION_CODES.O,
Build.VERSION_CODES.P,
Build.VERSION_CODES.CUR_DEVELOPMENT,
]
private def targetSdkVersionsWithLocationNeed = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.Q, Build.VERSION_CODES.CUR_DEVELOPMENT]

@Shared
private def sdkVersions = sdkVersionsPreM + sdkVersionsPostM
private def interestingVersions = targetSdkVersionsWithoutLocationNeed + targetSdkVersionsWithLocationNeed

@Shared
private def isAndroidWear = [true, false]
Expand All @@ -56,14 +47,19 @@ class LocationServicesStatusApi23Test extends Specification {
}

@Unroll
def "should check location provider only if needed (targetSdk:#targetSdk isAndroidWear:#isAndroidWearValue)"() {
def "should check location provider only if needed (deviceSdk:#deviceSdk targetSdk:#targetSdk isAndroidWear:#isAndroidWearValue)"() {
given:
mockApplicationTargetSdk = targetSdk
mockApplicationDeviceSdk = deviceSdk
mockIsAndroidWear = isAndroidWearValue
prepareObjectUnderTest()
int expectedCalls
if (targetSdk >= Build.VERSION_CODES.M && !isAndroidWearValue) {
if (isAndroidWearValue) {
expectedCalls = 0
} else if (deviceSdk >= Build.VERSION_CODES.Q) {
expectedCalls = 1
} else if (targetSdk >= Build.VERSION_CODES.M) {
expectedCalls = 1
} else {
expectedCalls = 0
Expand All @@ -76,6 +72,6 @@ class LocationServicesStatusApi23Test extends Specification {
expectedCalls * mockCheckerLocationProvider.isLocationProviderEnabled() >> true
where:
[targetSdk, isAndroidWearValue] << [sdkVersions, isAndroidWear].combinations()
[targetSdk, deviceSdk, isAndroidWearValue] << [interestingVersions, interestingVersions, isAndroidWear].combinations()
}
}

0 comments on commit 202b9ba

Please sign in to comment.