From df7a1b9991f3a9f1101773e45b21b44a8f612e8b Mon Sep 17 00:00:00 2001 From: DaVinci9196 <150454414+DaVinci9196@users.noreply.github.com> Date: Thu, 21 Mar 2024 05:53:53 +0800 Subject: [PATCH] Location: Implement settings request (#2216) For some applications that require GPS function, detect and remind the GPS to check in, such as Google Maps Co-authored-by: Marvin W --- .../java/org/microg/gms/DummyService.java | 39 +++++ play-services-location/build.gradle | 43 ++++++ play-services-location/core/build.gradle | 84 +++++++++++ .../core/src/main/AndroidManifest.xml | 62 ++++++++ .../gms/location/manager/LocationManager.kt | 4 +- .../manager/LocationManagerInstance.kt | 46 ++++-- .../DetailedLocationSettingsStates.kt | 72 +++++++++ .../LocationSettingsCheckerActivity.kt | 62 ++++++++ .../res/drawable/custom_dialog_background.xml | 6 + .../activity_location_setting_checker.xml | 100 +++++++++++++ .../src/main/res/values-zh-rCN/strings.xml | 33 +++++ .../core/src/main/res/values/strings.xml | 39 +++++ .../core/src/main/res/values/styles.xml | 10 ++ .../IGoogleLocationManagerService.aidl | 138 ++++++++++++++++++ .../gms/location/LocationSettingsRequest.java | 135 +++++++++++++++++ .../location/LocationSettingsResponse.java | 41 ++++++ .../gms/location/LocationSettingsResult.java | 86 +++++++++++ .../gms/location/LocationSettingsStates.java | 138 ++++++++++++++++++ .../android/gms/location/SettingsClient.java | 44 ++++++ .../gms/location/SettingsClientImpl.java | 39 +++++ 20 files changed, 1209 insertions(+), 12 deletions(-) create mode 100644 play-services-location/build.gradle create mode 100644 play-services-location/core/build.gradle create mode 100644 play-services-location/core/src/main/AndroidManifest.xml create mode 100644 play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/DetailedLocationSettingsStates.kt create mode 100644 play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt create mode 100644 play-services-location/core/src/main/res/drawable/custom_dialog_background.xml create mode 100644 play-services-location/core/src/main/res/layout/activity_location_setting_checker.xml create mode 100644 play-services-location/core/src/main/res/values-zh-rCN/strings.xml create mode 100644 play-services-location/core/src/main/res/values/strings.xml create mode 100644 play-services-location/core/src/main/res/values/styles.xml create mode 100644 play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl create mode 100644 play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java create mode 100644 play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResponse.java create mode 100644 play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResult.java create mode 100644 play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStates.java create mode 100644 play-services-location/src/main/java/com/google/android/gms/location/SettingsClient.java create mode 100644 play-services-location/src/main/java/org/microg/gms/location/SettingsClientImpl.java diff --git a/play-services-base-core/src/main/java/org/microg/gms/DummyService.java b/play-services-base-core/src/main/java/org/microg/gms/DummyService.java index 3fb2749a..5e19cc31 100644 --- a/play-services-base-core/src/main/java/org/microg/gms/DummyService.java +++ b/play-services-base-core/src/main/java/org/microg/gms/DummyService.java @@ -1,4 +1,5 @@ /* +<<<<<<< HEAD:play-services-base-core/src/main/java/org/microg/gms/DummyService.java * Copyright (C) 2013-2017 microG Project Team * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,16 +13,25 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. +======= + * SPDX-FileCopyrightText: 2017 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. +>>>>>>> 2e4d3ae4 (Location: Implement settings request (#2216)):play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStatusCodes.java */ package org.microg.gms; import android.os.RemoteException; +import androidx.annotation.NonNull; import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.internal.GetServiceRequest; import com.google.android.gms.common.internal.IGmsCallbacks; +<<<<<<< HEAD:play-services-base-core/src/main/java/org/microg/gms/DummyService.java import org.microg.gms.common.GmsService; public class DummyService extends BaseService { @@ -32,5 +42,34 @@ public class DummyService extends BaseService { @Override public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException { callback.onPostInitComplete(CommonStatusCodes.ERROR, null, null); +======= +import org.microg.gms.common.Hide; +import org.microg.gms.common.PublicApi; + +/** + * Location settings specific status codes, for use in {@link Status#getStatusCode()} + */ +@PublicApi +public class LocationSettingsStatusCodes extends CommonStatusCodes { + /** + * Location settings can't be changed to meet the requirements, no dialog pops up + */ + public static final int SETTINGS_CHANGE_UNAVAILABLE = 8502; + + @NonNull + @Hide + public static String getStatusCodeString(int statusCode) { + switch (statusCode) { + case SETTINGS_CHANGE_UNAVAILABLE: + return "SETTINGS_CHANGE_UNAVAILABLE"; + case 8500: + case 8501: + case 8503: + case 8505: + return "INTERNAL_LOCATION_SETTINGS_STATUS_CODE"; + default: + return CommonStatusCodes.getStatusCodeString(statusCode); + } +>>>>>>> 2e4d3ae4 (Location: Implement settings request (#2216)):play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStatusCodes.java } } diff --git a/play-services-location/build.gradle b/play-services-location/build.gradle new file mode 100644 index 00000000..9533fe51 --- /dev/null +++ b/play-services-location/build.gradle @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2015 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +android { + namespace "com.google.android.gms.location" + + compileSdkVersion androidCompileSdk + buildToolsVersion "$androidBuildVersionTools" + + buildFeatures { + aidl = true + } + + defaultConfig { + versionName version + minSdkVersion androidMinSdk + targetSdkVersion androidTargetSdk + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +apply from: '../gradle/publish-android.gradle' + +description = 'microG implementation of play-services-location' + +dependencies { + // Dependencies from play-services-location:21.0.1 + api project(':play-services-base') + api project(':play-services-basement') + api project(':play-services-tasks') + + annotationProcessor project(':safe-parcel-processor') +} diff --git a/play-services-location/core/build.gradle b/play-services-location/core/build.gradle new file mode 100644 index 00000000..a48c2259 --- /dev/null +++ b/play-services-location/core/build.gradle @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +dependencies { + api project(':play-services-location') + implementation project(':play-services-base-core') + implementation project(':play-services-location-core-base') + + implementation "androidx.core:core-ktx:$coreVersion" + implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion" + implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" + implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" + implementation "androidx.preference:preference-ktx:$preferenceVersion" + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion" + + implementation "com.android.volley:volley:$volleyVersion" + + compileOnly project(':play-services-maps') +} + +android { + namespace "org.microg.gms.location.core" + + compileSdkVersion androidCompileSdk + buildToolsVersion "$androidBuildVersionTools" + + buildFeatures { + buildConfig = true + } + + defaultConfig { + versionName version + minSdkVersion androidMinSdk + targetSdkVersion androidTargetSdk + buildConfigField "String", "ICHNAEA_KEY", "\"${localProperties.get("ichnaea.key", "")}\"" + buildConfigField "String", "FORCE_SHOW_BACKGROUND_PERMISSION", "\"\"" + buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "false" + } + + lintOptions { + disable 'MissingTranslation', 'GetLocales' + } + + flavorDimensions = ['target'] + productFlavors { + "default" { + dimension 'target' + } + "huawei" { + dimension 'target' + buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "true" + } + "huaweilh" { + dimension 'target' + buildConfigField "String", "FORCE_SHOW_BACKGROUND_PERMISSION", "\"com.huawei.permission.sec.MDM.v2\"" + buildConfigField "boolean", "SHOW_NOTIFICATION_WHEN_NOT_PERMITTED", "true" + } + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + huawei.java.srcDirs += 'src/huawei/kotlin' + huaweilh.java.srcDirs += huawei.java.srcDirs + huaweilh.res.srcDirs += huawei.res.srcDirs + } + + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + + kotlinOptions { + jvmTarget = 1.8 + } +} diff --git a/play-services-location/core/src/main/AndroidManifest.xml b/play-services-location/core/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ae320904 --- /dev/null +++ b/play-services-location/core/src/main/AndroidManifest.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt index 835adf9b..ecfef3d1 100644 --- a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt @@ -8,7 +8,6 @@ package org.microg.gms.location.manager import android.Manifest import android.app.Activity import android.app.PendingIntent -import android.app.PendingIntent.FLAG_MUTABLE import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.content.Context import android.content.Intent @@ -17,6 +16,7 @@ import android.location.Location import android.os.* import android.os.Build.VERSION.SDK_INT import android.util.Log +import androidx.core.app.PendingIntentCompat import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.core.location.LocationListenerCompat @@ -146,7 +146,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life } val intent = Intent(context, LocationManagerService::class.java) intent.action = LocationManagerService.ACTION_REPORT_LOCATION - coarsePendingIntent = PendingIntent.getService(context, 0, intent, (if (SDK_INT >= 31) FLAG_MUTABLE else 0) or FLAG_UPDATE_CURRENT) + coarsePendingIntent = PendingIntentCompat.getService(context, 0, intent, FLAG_UPDATE_CURRENT, true) lastLocationCapsule.start() requestManager.start() } diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerInstance.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerInstance.kt index 689d780a..0e1e7cc4 100644 --- a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerInstance.kt +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerInstance.kt @@ -7,16 +7,22 @@ package org.microg.gms.location.manager import android.Manifest.permission.* import android.app.PendingIntent +import android.bluetooth.BluetoothManager import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager import android.content.pm.PackageManager.PERMISSION_GRANTED import android.location.Location import android.location.LocationManager.GPS_PROVIDER import android.location.LocationManager.NETWORK_PROVIDER import android.os.Binder +import android.os.Build.VERSION.SDK_INT import android.os.IBinder import android.os.Parcel import android.os.SystemClock +import android.provider.Settings import android.util.Log +import androidx.core.app.PendingIntentCompat import androidx.core.content.getSystemService import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner @@ -25,13 +31,14 @@ import com.google.android.gms.common.api.CommonStatusCodes import com.google.android.gms.common.api.Status import com.google.android.gms.common.api.internal.IStatusCallback import com.google.android.gms.common.internal.ICancelToken +import com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer import com.google.android.gms.location.* import com.google.android.gms.location.internal.* import com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData.REMOVE_UPDATES import com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData.REQUEST_UPDATES import kotlinx.coroutines.* -import org.microg.gms.common.NonCancelToken import org.microg.gms.location.hasNetworkLocationServiceBuiltIn +import org.microg.gms.location.settings.* import org.microg.gms.utils.warnOnTransactionIssues class LocationManagerInstance( @@ -209,17 +216,36 @@ class LocationManagerInstance( } override fun requestLocationSettingsDialog(settingsRequest: LocationSettingsRequest?, callback: ISettingsCallbacks?, packageName: String?) { - Log.d(TAG, "requestLocationSettingsDialog by ${getClientIdentity().packageName}") + Log.d(TAG, "requestLocationSettingsDialog by ${getClientIdentity().packageName} $settingsRequest") val clientIdentity = getClientIdentity() lifecycleScope.launchWhenStarted { - val locationManager = context.getSystemService() - val gpsPresent = locationManager?.allProviders?.contains(GPS_PROVIDER) == true - val networkPresent = locationManager?.allProviders?.contains(NETWORK_PROVIDER) == true || context.hasNetworkLocationServiceBuiltIn() - val gpsUsable = gpsPresent && locationManager?.isProviderEnabled(GPS_PROVIDER) == true && - context.packageManager.checkPermission(ACCESS_FINE_LOCATION, clientIdentity.packageName) == PERMISSION_GRANTED - val networkUsable = networkPresent && locationManager?.isProviderEnabled(NETWORK_PROVIDER) == true && - context.packageManager.checkPermission(ACCESS_COARSE_LOCATION, clientIdentity.packageName) == PERMISSION_GRANTED - runCatching { callback?.onLocationSettingsResult(LocationSettingsResult(LocationSettingsStates(gpsUsable, networkUsable, false, gpsPresent, networkPresent, true), Status.SUCCESS)) } + val states = context.getDetailedLocationSettingsStates() + val requests = settingsRequest?.requests?.map { + it.priority to (if (it.granularity == Granularity.GRANULARITY_PERMISSION_LEVEL) context.granularityFromPermission(clientIdentity) else it.granularity) + }.orEmpty() + val gpsRequested = requests.any { it.first == Priority.PRIORITY_HIGH_ACCURACY && it.second == Granularity.GRANULARITY_FINE } + val networkLocationRequested = requests.any { it.first <= Priority.PRIORITY_LOW_POWER && it.second >= Granularity.GRANULARITY_COARSE } + val bleRequested = settingsRequest?.needBle == true + val statusCode = when { + gpsRequested && states.gpsPresent && !states.gpsUsable -> CommonStatusCodes.RESOLUTION_REQUIRED + networkLocationRequested && states.networkLocationPresent && !states.networkLocationUsable -> CommonStatusCodes.RESOLUTION_REQUIRED + bleRequested && states.blePresent && !states.bleUsable -> CommonStatusCodes.RESOLUTION_REQUIRED + gpsRequested && !states.gpsPresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE + networkLocationRequested && !states.networkLocationPresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE + bleRequested && !states.blePresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE + else -> CommonStatusCodes.SUCCESS + } + + val resolution = if (statusCode == CommonStatusCodes.RESOLUTION_REQUIRED) { + val intent = Intent(ACTION_LOCATION_SETTINGS_CHECKER) + intent.setPackage(context.packageName) + intent.putExtra(EXTRA_ORIGINAL_PACKAGE_NAME, clientIdentity.packageName) + intent.putExtra(EXTRA_SETTINGS_REQUEST, SafeParcelableSerializer.serializeToBytes(settingsRequest)) + PendingIntentCompat.getActivity(context, clientIdentity.packageName.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT, true) + } else null + val status = Status(statusCode, LocationSettingsStatusCodes.getStatusCodeString(statusCode), resolution) + Log.d(TAG, "requestLocationSettingsDialog by ${getClientIdentity().packageName} returns $status") + runCatching { callback?.onLocationSettingsResult(LocationSettingsResult(status, states.toApi())) } } } diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/DetailedLocationSettingsStates.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/DetailedLocationSettingsStates.kt new file mode 100644 index 00000000..13f6ef45 --- /dev/null +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/DetailedLocationSettingsStates.kt @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2024 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.location.settings + +import android.Manifest.permission.* +import android.bluetooth.BluetoothManager +import android.content.Context +import android.content.pm.PackageManager.* +import android.location.LocationManager +import android.location.LocationManager.GPS_PROVIDER +import android.location.LocationManager.NETWORK_PROVIDER +import android.os.Build.VERSION.SDK_INT +import android.provider.Settings +import androidx.core.content.getSystemService +import com.google.android.gms.location.LocationSettingsStates +import org.microg.gms.location.hasNetworkLocationServiceBuiltIn + +data class DetailedLocationSettingsStates( + val gpsSystemFeature: Boolean, + val networkLocationSystemFeature: Boolean, + val bluetoothLeSystemFeature: Boolean, + val gpsProviderEnabled: Boolean, + val networkLocationProviderEnabled: Boolean, + val networkLocationProviderBuiltIn: Boolean, + val fineLocationPermission: Boolean, + val coarseLocationPermission: Boolean, + val backgroundLocationPermission: Boolean, + val blePresent: Boolean, + val bleEnabled: Boolean, + val bleScanAlways: Boolean, + val airplaneMode: Boolean, +) { + val gpsPresent: Boolean + get() = gpsSystemFeature + val networkLocationPresent: Boolean + get() = networkLocationSystemFeature || networkLocationProviderBuiltIn + val gpsUsable: Boolean + get() = gpsProviderEnabled && fineLocationPermission && backgroundLocationPermission + val networkLocationUsable: Boolean + get() = (networkLocationProviderEnabled || networkLocationProviderBuiltIn) && coarseLocationPermission && backgroundLocationPermission + val bleUsable: Boolean + get() = blePresent && (bleEnabled || (bleScanAlways && !airplaneMode)) + + fun toApi() = LocationSettingsStates(gpsUsable, networkLocationUsable, bleUsable, gpsPresent, networkLocationPresent, blePresent) +} + +fun Context.getDetailedLocationSettingsStates(): DetailedLocationSettingsStates { + val bluetoothLeSystemFeature = packageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) + val locationManager = getSystemService() + val bluetoothManager = if (bluetoothLeSystemFeature) getSystemService() else null + val bleAdapter = bluetoothManager?.adapter + + return DetailedLocationSettingsStates( + gpsSystemFeature = packageManager.hasSystemFeature(FEATURE_LOCATION_GPS), + networkLocationSystemFeature = packageManager.hasSystemFeature(FEATURE_LOCATION_NETWORK), + bluetoothLeSystemFeature = bluetoothLeSystemFeature, + gpsProviderEnabled = locationManager?.isProviderEnabled(GPS_PROVIDER) == true, + networkLocationProviderEnabled = locationManager?.isProviderEnabled(NETWORK_PROVIDER) == true, + networkLocationProviderBuiltIn = hasNetworkLocationServiceBuiltIn(), + fineLocationPermission = packageManager.checkPermission(ACCESS_FINE_LOCATION, packageName) == PERMISSION_GRANTED, + coarseLocationPermission = packageManager.checkPermission(ACCESS_COARSE_LOCATION, packageName) == PERMISSION_GRANTED, + backgroundLocationPermission = if (SDK_INT < 29) true else + packageManager.checkPermission(ACCESS_BACKGROUND_LOCATION, packageName) == PERMISSION_GRANTED, + blePresent = bleAdapter != null, + bleEnabled = bleAdapter?.isEnabled == true, + bleScanAlways = Settings.Global.getInt(contentResolver, "ble_scan_always_enabled", 0) == 1, + airplaneMode = Settings.Global.getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) != 0 + ) +} \ No newline at end of file diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt new file mode 100644 index 00000000..d30fc22e --- /dev/null +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.location.settings + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.location.LocationManager +import android.os.Bundle +import android.provider.Settings +import android.util.Log +import android.widget.TextView +import org.microg.gms.location.core.R + +const val ACTION_LOCATION_SETTINGS_CHECKER = "com.google.android.gms.location.settings.CHECK_SETTINGS" + +private const val REQUEST_CODE_LOCATION = 120 +const val EXTRA_ORIGINAL_PACKAGE_NAME = "originalPackageName" +const val EXTRA_SETTINGS_REQUEST = "locationSettingsRequests" + +class LocationSettingsCheckerActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_location_setting_checker) + + findViewById(R.id.location_setting_checker_sure).setOnClickListener { + // TODO: We also should handle permissions, Airplane Mode and BLE here. + val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) + startActivityForResult(intent, REQUEST_CODE_LOCATION) + } + findViewById(R.id.location_setting_checker_cancel).setOnClickListener { + checkerBack(RESULT_CANCELED) + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == REQUEST_CODE_LOCATION && isLocationEnabled(this)) { + checkerBack(RESULT_OK) + } else { + super.onActivityResult(requestCode, resultCode, data) + } + } + + override fun onBackPressed() { + checkerBack(RESULT_CANCELED) + } + + private fun checkerBack(resultCode: Int) { + setResult(resultCode) + finish() + } + + private fun isLocationEnabled(context: Context): Boolean { + val locationManager = context.getSystemService(LOCATION_SERVICE) as LocationManager + return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) || locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) + } + +} \ No newline at end of file diff --git a/play-services-location/core/src/main/res/drawable/custom_dialog_background.xml b/play-services-location/core/src/main/res/drawable/custom_dialog_background.xml new file mode 100644 index 00000000..c4f7f602 --- /dev/null +++ b/play-services-location/core/src/main/res/drawable/custom_dialog_background.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/play-services-location/core/src/main/res/layout/activity_location_setting_checker.xml b/play-services-location/core/src/main/res/layout/activity_location_setting_checker.xml new file mode 100644 index 00000000..0c0af3c6 --- /dev/null +++ b/play-services-location/core/src/main/res/layout/activity_location_setting_checker.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/play-services-location/core/src/main/res/values-zh-rCN/strings.xml b/play-services-location/core/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 00000000..8acdb05d --- /dev/null +++ b/play-services-location/core/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,33 @@ + + + 从 Mozilla 位置服务获取基于 Wi-Fi 的位置信息 + 使用 GPS时,在本地存储 Wi-Fi 网络的位置信息 + 最后访问于%1$s + 向 Mozilla 发出请求 + 使用 GPS时,在本地存储移动网络的位置信息 + 可访问位置信息的应用 + 无视应用的位置权限级别,总是向其提供大致的位置信息。 + 从 GPS 处学习 + 从 GPS 处学习 + 当连接到受支持的热点网络时,从上游热点直接获取 Wi-Fi 位置信息 + 基于移动网络的位置信息 + 向 Mozilla 发出请求 + 向热点发出请求 + 总是提供大致的位置 + 使用 Nominatim + 位置信息 + 最近访问 + 使用 OpenStreetMap Nominatim 服务解析地址 + 基于 Wi-Fi 的位置信息 + 地址解析器 + 从 Mozilla 位置服务获取移动网络信号塔位置 + + 要继续,请开启设备位置信息功能\n(使用位置信息服务) + 您的设备将需要: + 使用GPS、WLAN、移动网络和传感器 + 使用位置信息服务;在提供该服务的过程中,可能会定期收集位置数据,并以匿名方式使用这类数据,从而提高位置信息的精准度并改善基于地理位置的服务。 + 有关详细信息,请访问 位置信息设置。 + 不用了 + 确定 + + \ No newline at end of file diff --git a/play-services-location/core/src/main/res/values/strings.xml b/play-services-location/core/src/main/res/values/strings.xml new file mode 100644 index 00000000..6bb75c0f --- /dev/null +++ b/play-services-location/core/src/main/res/values/strings.xml @@ -0,0 +1,39 @@ + + + + Location + Recent access + Wi-Fi location + Mobile network location + Address resolver + Request from Mozilla + Fetch Wi-Fi-based location from Mozilla Location Service. + Request from Hotspot + Fetch Wi-Fi location directly from supported hotspots when connected. + Remember from GPS + Store Wi-Fi locations locally when GPS is used. + Request from Mozilla + Fetch mobile network cell tower locations from Mozilla Location Service. + Remember from GPS + Store mobile network locations locally when GPS is used. + Use Nominatim + Resolve addresses using OpenStreetMap Nominatim. + + Apps with location access + Last access: %1$s + + Force coarse location + Always return coarse locations to this app, ignoring its permission level. + + To continue, turn on device location, which uses location service + Your device will need to: + Use GPS, Wi‑Fi, cell networks, and sensors + Use location service; as part of this service, may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services. + For details, go to the location settings. + No,thanks + OK + + \ No newline at end of file diff --git a/play-services-location/core/src/main/res/values/styles.xml b/play-services-location/core/src/main/res/values/styles.xml new file mode 100644 index 00000000..98bbf26a --- /dev/null +++ b/play-services-location/core/src/main/res/values/styles.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl b/play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl new file mode 100644 index 00000000..d848199f --- /dev/null +++ b/play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl @@ -0,0 +1,138 @@ +package com.google.android.gms.location.internal; + +import android.app.PendingIntent; +import android.location.Location; +import android.os.Bundle; + +import com.google.android.gms.common.api.Status; +import com.google.android.gms.common.api.internal.IStatusCallback; +import com.google.android.gms.common.internal.ICancelToken; +import com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData; +import com.google.android.gms.location.internal.IFusedLocationProviderCallback; +import com.google.android.gms.location.internal.IGeofencerCallbacks; +import com.google.android.gms.location.internal.ILocationStatusCallback; +import com.google.android.gms.location.internal.ISettingsCallbacks; +import com.google.android.gms.location.internal.LocationReceiver; +import com.google.android.gms.location.internal.LocationRequestInternal; +import com.google.android.gms.location.internal.LocationRequestUpdateData; +import com.google.android.gms.location.internal.ParcelableGeofence; +import com.google.android.gms.location.ActivityRecognitionResult; +import com.google.android.gms.location.ActivityRecognitionRequest; +import com.google.android.gms.location.ActivityTransitionRequest; +import com.google.android.gms.location.CurrentLocationRequest; +import com.google.android.gms.location.GeofencingRequest; +import com.google.android.gms.location.GestureRequest; +import com.google.android.gms.location.ILocationListener; +import com.google.android.gms.location.LastLocationRequest; +import com.google.android.gms.location.LocationAvailability; +import com.google.android.gms.location.LocationAvailabilityRequest; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationSettingsRequest; +import com.google.android.gms.location.LocationStatus; +import com.google.android.gms.location.SleepSegmentRequest; + +interface IGoogleLocationManagerService { + + // current + + void addGeofences(in GeofencingRequest geofencingRequest, in PendingIntent pendingIntent, IGeofencerCallbacks callbacks) = 56; + void removeGeofencesByIntent(in PendingIntent pendingIntent, IGeofencerCallbacks callbacks, String packageName) = 1; + void removeGeofencesById(in String[] geofenceRequestIds, IGeofencerCallbacks callbacks, String packageName) = 2; + + void removeActivityTransitionUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 72; + void removeActivityUpdates(in PendingIntent callbackIntent) = 5; + void requestActivityTransitionUpdates(in ActivityTransitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 71; + void requestActivityUpdates(long detectionIntervalMillis, boolean triggerUpdates, in PendingIntent callbackIntent) = 4; + void requestActivityUpdatesWithCallback(in ActivityRecognitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 69; + + Location getLastLocation() = 6; + void getLastLocationWithRequest(in LastLocationRequest request, ILocationStatusCallback callback) = 81; + void getLastLocationWithReceiver(in LastLocationRequest request, in LocationReceiver receiver) = 89; + + ICancelToken getCurrentLocation(in CurrentLocationRequest request, ILocationStatusCallback callback) = 86; + ICancelToken getCurrentLocationWithReceiver(in CurrentLocationRequest request, in LocationReceiver receiver) = 91; + + void requestLocationUpdatesWithCallback(in LocationReceiver receiver, in LocationRequest request, IStatusCallback callback) = 87; + void removeLocationUpdatesWithCallback(in LocationReceiver receiver, IStatusCallback callback) = 88; + void updateLocationRequest(in LocationRequestUpdateData locationRequestUpdateData) = 58; + + void flushLocations(IFusedLocationProviderCallback callback) = 66; + + LocationAvailability getLocationAvailabilityWithPackage(String packageName) = 33; + void getLocationAvailabilityWithReceiver(in LocationAvailabilityRequest request, in LocationReceiver receiver) = 90; + + void setMockMode(boolean mockMode) = 11; + void setMockLocation(in Location mockLocation) = 12; + void setMockModeWithCallback(boolean mockMode, IStatusCallback callback) = 83; + void setMockLocationWithCallback(in Location mockLocation, IStatusCallback callback) = 84; + + void removeSleepSegmentUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 68; + void requestSleepSegmentUpdates(in PendingIntent pendingIntent, in SleepSegmentRequest request, IStatusCallback callback) = 78; + + void requestLocationSettingsDialog(in LocationSettingsRequest settingsRequest, ISettingsCallbacks callback, String packageName) = 62; + + void updateDeviceOrientationRequest(in DeviceOrientationRequestUpdateData request) = 74; + + // deprecated + + void addGeofencesList(in List geofences, in PendingIntent pendingIntent, IGeofencerCallbacks callbacks, String packageName) = 0; + void removeAllGeofences(IGeofencerCallbacks callbacks, String packageName) = 3; + + ActivityRecognitionResult getLastActivity(String packageName) = 63; + + Location getLastLocationWithPackage(String packageName) = 20; + Location getLastLocationWith(String s) = 79; + + void requestLocationUpdatesWithListener(in LocationRequest request, ILocationListener listener) = 7; + void requestLocationUpdatesWithPackage(in LocationRequest request, ILocationListener listener, String packageName) = 19; + void requestLocationUpdatesWithIntent(in LocationRequest request, in PendingIntent callbackIntent) = 8; + void requestLocationUpdatesInternalWithListener(in LocationRequestInternal request, ILocationListener listener) = 51; + void requestLocationUpdatesInternalWithIntent(in LocationRequestInternal request, in PendingIntent callbackIntent) = 52; + void removeLocationUpdatesWithListener(ILocationListener listener) = 9; + void removeLocationUpdatesWithIntent(in PendingIntent callbackIntent) = 10; + + // unsupported + +// void iglms14(in LatLngBounds var1, int var2, in PlaceFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 13; +// void iglms15(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 14; +// void iglms16(in LatLng var1, in PlaceFilter var2, in PlacesParams var3, IPlacesCallbacks var4) = 15; +// void iglms17(in PlaceFilter var1, in PlacesParams var2, IPlacesCallbacks var3) = 16; +// void iglms18(in PlaceRequest var1, in PlacesParams var2, in PendingIntent var3) = 17; +// void iglms19(in PlacesParams var1, in PendingIntent var2) = 18; + +// void iglms25(in PlaceReport var1, in PlacesParams var2) = 24; +// void injectLocation(in Location mockLocation, int injectionType) = 25; + +// void iglms42(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 41; + +// void iglms46(in UserAddedPlace var1, in PlacesParams var2, IPlacesCallbacks var3) = 45; +// void iglms47(in LatLngBounds var1, int var2, String var3, in PlaceFilter var4, in PlacesParams var5, IPlacesCallbacks var6) = 46; +// void iglms48(in NearbyAlertRequest var1, in PlacesParams var2, in PendingIntent var3) = 47; +// void iglms49(in PlacesParams var1, in PendingIntent var2) = 48; +// void iglms50(in UserDataType var1, in LatLngBounds var2, in List var3, in PlacesParams var4, IPlacesCallbacks var5) = 49; +// IBinder iglms51() = 50; + +// IBinder iglms54() = 53; +// void iglms55(String var1, in LatLngBounds var2, in AutocompleteFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 54; + +// void iglms58(in List var1, in PlacesParams var2, IPlacesCallbacks var3) = 57; + +// Status requestGestureUpdates(in GestureRequest request, in PendingIntent pendingIntent) = 59; +// Status iglms61(in PendingIntent pendingIntent) = 60; + +// void iglms65(in PendingIntent pendingIntent, IStatusCallback callback) = 64; +// void iglms66(in PendingIntent pendingIntent, IStatusCallback callback) = 65; + +// void iglms68(in PendingIntent pendingIntent, IStatusCallback callback) = 67; + +// void iglms71(IStatusCallback callback) = 70; + +// void removeGeofences(in RemoveGeofencingRequest request, IGeofencerCallbacks callback) = 73; +// void iglms76(in PendingIntent pendingIntent) = 75; +// boolean setActivityRecognitionMode(int mode) = 76; +// int getActivityRecognitionMode() = 77; + +// void injectLocatinWithCallback(in Location mockLocation, int injectionType, IStatusCallback callback) = 85; + +// void isGoogleLocationAccuracyEnabled(in IBooleanStatusCallback callback) = 94; +} diff --git a/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java new file mode 100644 index 00000000..786d6cb4 --- /dev/null +++ b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java @@ -0,0 +1,135 @@ +/* + * SPDX-FileCopyrightText: 2015 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. + */ + +package com.google.android.gms.location; + +import android.os.Parcel; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter; +import org.microg.gms.common.Hide; +import org.microg.gms.common.PublicApi; +import org.microg.gms.utils.ToStringHelper; +import org.microg.safeparcel.AutoSafeParcelable; +import org.microg.safeparcel.SafeParceled; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Specifies the types of location services the client is interested in using. Settings will be checked for optimal functionality + * of all requested services. Use {@link LocationSettingsRequest.Builder} to construct this object. + */ +@PublicApi +@SafeParcelable.Class +public class LocationSettingsRequest extends AbstractSafeParcelable { + @Field(1000) + private int versionCode = 2; + + @Field(value = 1, subClass = LocationRequest.class) + @Hide + public final List requests; + + @Field(2) + @Hide + public final boolean alwaysShow; + + @Field(3) + @Hide + public final boolean needBle; + + @Field(5) + @Hide + @Nullable + public final LocationSettingsConfiguration configuration; + + @Constructor + LocationSettingsRequest(@Param(1) List requests, @Param(2) boolean alwaysShow, @Param(3) boolean needBle, @Param(5) @Nullable LocationSettingsConfiguration configuration) { + this.requests = requests; + this.alwaysShow = alwaysShow; + this.needBle = needBle; + this.configuration = configuration; + } + + /** + * A builder that builds {@link LocationSettingsRequest}. + */ + public static class Builder { + private List requests = new ArrayList(); + private boolean alwaysShow = false; + private boolean needBle = false; + + /** + * Adds a collection of {@link LocationRequest}s that the client is interested in. Settings + * will be checked for optimal performance of all {@link LocationRequest}s. + */ + public Builder addAllLocationRequests(Collection requests) { + this.requests.addAll(requests); + return this; + } + + /** + * Adds one {@link LocationRequest} that the client is interested in. Settings will be + * checked for optimal performance of all {@link LocationRequest}s. + */ + public Builder addLocationRequest(LocationRequest request) { + requests.add(request); + return this; + } + + /** + * Creates a LocationSettingsRequest that can be used with SettingsApi. + */ + public LocationSettingsRequest build() { + return new LocationSettingsRequest(requests, alwaysShow, needBle, null); + } + + /** + * Whether or not location is required by the calling app in order to continue. Set this to + * true if location is required to continue and false if having location provides better + * results, but is not required. This changes the wording/appearance of the dialog + * accordingly. + */ + public Builder setAlwaysShow(boolean show) { + alwaysShow = show; + return this; + } + + /** + * Sets whether the client wants BLE scan to be enabled. When this flag is set to true, if + * the platform supports BLE scan mode and Bluetooth is off, the dialog will prompt the + * user to enable BLE scan. If the platform doesn't support BLE scan mode, the dialog will + * prompt to enable Bluetooth. + */ + public Builder setNeedBle(boolean needBle) { + this.needBle = needBle; + return this; + } + } + + @Hide + @NonNull + @Override + public String toString() { + return ToStringHelper.name("LocationSettingsRequest") + .value(requests) + .field("alwaysShow", alwaysShow) + .field("needBle", needBle) + .end(); + } + + public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(LocationSettingsRequest.class); + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + CREATOR.writeToParcel(this, dest, flags); + } +} diff --git a/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResponse.java b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResponse.java new file mode 100644 index 00000000..dbe22a08 --- /dev/null +++ b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResponse.java @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. + */ + +package com.google.android.gms.location; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResolvableApiException; +import com.google.android.gms.common.api.Response; +import com.google.android.gms.tasks.Task; +import org.microg.gms.common.Hide; +import org.microg.gms.common.PublicApi; + +/** + * Successful response of checking settings via {@link SettingsApi#checkLocationSettings(GoogleApiClient, LocationSettingsRequest)}. + *

+ * If a {@link Task} with this response type fails, it will receive a {@link ResolvableApiException} which may be able to resolve the failure. + * See {@link SettingsClient} for more details. + *

+ * The current location settings states can be accessed via {@link #getLocationSettingsStates()}. See {@link LocationSettingsStates} for more details. + */ +public class LocationSettingsResponse extends Response { + /** + * Retrieves the location settings states. + */ + @Nullable + public LocationSettingsStates getLocationSettingsStates() { + return getResult().getLocationSettingsStates(); + } + + @Hide + public LocationSettingsResponse(@NonNull LocationSettingsResult result) { + super(result); + } +} diff --git a/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResult.java b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResult.java new file mode 100644 index 00000000..62e00c26 --- /dev/null +++ b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResult.java @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2015 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. + */ + +package com.google.android.gms.location; + +import android.app.Activity; +import android.os.Parcel; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.Result; +import com.google.android.gms.common.api.Status; + +import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter; +import org.microg.gms.common.Hide; +import org.microg.gms.common.PublicApi; + +/** + * Result of checking settings via {@link SettingsApi#checkLocationSettings(GoogleApiClient, LocationSettingsRequest)}, + * indicates whether a dialog should be shown to ask the user's consent to change their + * settings. + *

+ * The method {@link #getStatus()} can be used to confirm if the request was successful. If the current location settings don't + * satisfy the app's requirements and the user has permission to change the settings, the app could use + * {@link Status#startResolutionForResult(Activity, int)} to start an intent to show a dialog, asking for user's consent to + * change the settings. + *

+ * The current location settings states can be accessed via {@link #getLocationSettingsStates()}. See + * {@link LocationSettingsStates} for more details. + */ +@PublicApi +@SafeParcelable.Class +public class LocationSettingsResult extends AbstractSafeParcelable implements Result { + + @Field(1000) + int versionCode = 1; + + @Field(1) + @NonNull + private final Status status; + + @Field(2) + @Nullable + private final LocationSettingsStates settings; + + + /** + * Retrieves the location settings states. + */ + @Nullable + public LocationSettingsStates getLocationSettingsStates() { + return settings; + } + + @Override + @NonNull + public Status getStatus() { + return status; + } + + @Hide + @Constructor + public LocationSettingsResult(@Param(1) @NonNull Status status, @Param(2) @Nullable LocationSettingsStates settings) { + this.settings = settings; + this.status = status; + } + + @Hide + public LocationSettingsResult(@NonNull Status status) { + this(status, null); + } + + public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(LocationSettingsResult.class); + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + CREATOR.writeToParcel(this, dest, flags); + } +} diff --git a/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStates.java b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStates.java new file mode 100644 index 00000000..e2f6d02b --- /dev/null +++ b/play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStates.java @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2015 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. + */ + +package com.google.android.gms.location; + +import android.app.Activity; +import android.content.Intent; +import android.os.Parcel; +import androidx.annotation.NonNull; +import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelable; +import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter; +import com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer; +import org.microg.gms.common.PublicApi; + +/** + * Stores the current states of all location-related settings. + */ +@PublicApi +@SafeParcelable.Class +public class LocationSettingsStates extends AbstractSafeParcelable { + + @Field(1000) + int versionCode = 2; + + @Field(1) + private final boolean gpsUsable; + + @Field(2) + private final boolean networkLocationUsable; + + @Field(3) + private final boolean bleUsable; + + @Field(4) + private final boolean gpsPresent; + + @Field(5) + private final boolean networkLocationPresent; + + @Field(6) + private final boolean blePresent; + + /** + * Whether BLE is present on the device. + */ + public boolean isBlePresent() { + return blePresent; + } + + /** + * Whether BLE is enabled and is usable by the app. + */ + public boolean isBleUsable() { + return bleUsable; + } + + /** + * Whether GPS provider is present on the device. + */ + public boolean isGpsPresent() { + return gpsPresent; + } + + /** + * Whether GPS provider is enabled and is usable by the app. + */ + public boolean isGpsUsable() { + return gpsUsable; + } + + /** + * Whether location is present on the device. + *

+ * This method returns true when either GPS or network location provider is present. + */ + public boolean isLocationPresent() { + return isGpsPresent() || isNetworkLocationPresent(); + } + + /** + * Whether location is enabled and is usable by the app. + *

+ * This method returns true when either GPS or network location provider is usable. + */ + public boolean isLocationUsable() { + return isGpsUsable() || isNetworkLocationUsable(); + } + + /** + * Whether network location provider is present on the device. + */ + public boolean isNetworkLocationPresent() { + return networkLocationPresent; + } + + /** + * Whether network location provider is enabled and usable by the app. + */ + public boolean isNetworkLocationUsable() { + return networkLocationUsable; + } + + @Constructor + public LocationSettingsStates(@Param(1) boolean gpsUsable, @Param(2) boolean networkLocationUsable, @Param(3) boolean bleUsable, @Param(4) boolean gpsPresent, @Param(5) boolean networkLocationPresent, @Param(6) boolean blePresent) { + this.gpsUsable = gpsUsable; + this.networkLocationUsable = networkLocationUsable; + this.bleUsable = bleUsable; + this.gpsPresent = gpsPresent; + this.networkLocationPresent = networkLocationPresent; + this.blePresent = blePresent; + } + + /** + * Retrieves the location settings states from the intent extras. When the location settings dialog finishes, you can use this + * method to retrieve the current location settings states from the intent in your + * {@link Activity#onActivityResult(int, int, Intent)}. + */ + public static LocationSettingsStates fromIntent(Intent intent) { + byte[] bytes = intent.getByteArrayExtra(EXTRA_NAME); + if (bytes == null) return null; + return SafeParcelableSerializer.deserializeFromBytes(bytes, CREATOR); + } + + public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(LocationSettingsStates.class); + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + CREATOR.writeToParcel(this, dest, flags); + } + + private static final String EXTRA_NAME = "com.google.android.gms.location.LOCATION_SETTINGS_STATES"; +} diff --git a/play-services-location/src/main/java/com/google/android/gms/location/SettingsClient.java b/play-services-location/src/main/java/com/google/android/gms/location/SettingsClient.java new file mode 100644 index 00000000..4c485d72 --- /dev/null +++ b/play-services-location/src/main/java/com/google/android/gms/location/SettingsClient.java @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + * Notice: Portions of this file are reproduced from work created and shared by Google and used + * according to terms described in the Creative Commons 4.0 Attribution License. + * See https://developers.google.com/readme/policies for details. + */ + +package com.google.android.gms.location; + +import android.location.LocationManager; +import android.provider.Settings; +import com.google.android.gms.common.api.Api; +import com.google.android.gms.common.api.HasApiKey; +import com.google.android.gms.tasks.Task; + +/** + * The main entry point for interacting with the location settings-enabler APIs. + *

+ * This API makes it easy for an app to ensure that the device's system settings are properly configured for the app's + * location needs. + */ +public interface SettingsClient extends HasApiKey { + /** + * Checks if the relevant system settings are enabled on the device to carry out the desired location requests. + * + * @param locationSettingsRequest an object that contains all the location requirements that the client is interested in. + */ + Task checkLocationSettings(LocationSettingsRequest locationSettingsRequest); + + /** + * Returns true if the Google Location Accuracy setting is currently enabled. This setting is required for Fused Location + * Provider APIs to be able to generate network (wifi, cell, etc) based locations. If Google Play services is chosen as the + * platform {@link LocationManager#NETWORK_PROVIDER} (this is the case on all GMS compliant devices, which constitute the + * vast majority of the Android ecosystem), then this setting is also required for the platform + * {@link LocationManager#NETWORK_PROVIDER} to be enabled. + *

+ * On Android P and above devices, the Google Location Accuracy setting may be found under location settings. Below + * Android P, Google Location Accuracy is tied to the device location mode - it will be enabled if the device is in + * {@link Settings.Secure#LOCATION_MODE_BATTERY_SAVING} or {@link Settings.Secure#LOCATION_MODE_HIGH_ACCURACY}, and + * disabled in {@link Settings.Secure#LOCATION_MODE_SENSORS_ONLY}. + */ + Task isGoogleLocationAccuracyEnabled(); +} diff --git a/play-services-location/src/main/java/org/microg/gms/location/SettingsClientImpl.java b/play-services-location/src/main/java/org/microg/gms/location/SettingsClientImpl.java new file mode 100644 index 00000000..f8d89125 --- /dev/null +++ b/play-services-location/src/main/java/org/microg/gms/location/SettingsClientImpl.java @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.location; + +import android.content.Context; + +import android.os.RemoteException; +import com.google.android.gms.common.api.Api; +import com.google.android.gms.common.api.GoogleApi; +import com.google.android.gms.location.*; +import com.google.android.gms.location.internal.ISettingsCallbacks; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskCompletionSource; +import com.google.android.gms.tasks.Tasks; +import org.microg.gms.common.api.PendingGoogleApiCall; + +public class SettingsClientImpl extends GoogleApi implements SettingsClient { + public SettingsClientImpl(Context context) { + super(context, LocationServices.API); + } + + @Override + public Task checkLocationSettings(LocationSettingsRequest locationSettingsRequest) { + return scheduleTask((PendingGoogleApiCall) (client, completionSource) -> client.getServiceInterface().requestLocationSettingsDialog(locationSettingsRequest, new ISettingsCallbacks.Stub() { + @Override + public void onLocationSettingsResult(LocationSettingsResult result) { + completionSource.setResult(new LocationSettingsResponse(result)); + } + }, null)); + } + + @Override + public Task isGoogleLocationAccuracyEnabled() { + return Tasks.forResult(true); // TODO + } +}