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 <git@larma.de>
This commit is contained in:
DaVinci9196 2024-03-21 05:53:53 +08:00 • committed by Cuynu
commit df7a1b9991
20 changed files with 1209 additions and 12 deletions

View file

@ -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
}
}

View file

@ -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')
}

View file

@ -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
}
}

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ SPDX-FileCopyrightText: 2020 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission
android:name="android.permission.UPDATE_DEVICE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission
android:name="android.permission.UPDATE_APP_OPS_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission
android:name="android.permission.WATCH_APPOPS"
tools:ignore="ProtectedPermissions" />
<application>
<activity
android:name="org.microg.gms.location.settings.LocationSettingsCheckerActivity"
android:excludeFromRecents="true"
android:exported="false"
android:process=":ui"
android:theme="@style/AlertThemeSelector">
<intent-filter android:priority="-1">
<action android:name="com.google.android.gms.location.settings.CHECK_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="org.microg.gms.location.manager.AskPermissionActivity"
android:excludeFromRecents="true"
android:process=":ui"
android:theme="@style/Theme.Translucent"
android:exported="false" />
<service
android:name="org.microg.gms.location.manager.LocationManagerService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.location.internal.GoogleLocationManagerService.START" />
</intent-filter>
</service>
<service
android:name="org.microg.gms.location.reporting.ReportingAndroidService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.location.reporting.service.START" />
<action android:name="com.google.android.gms.location.reporting.service.START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
</manifest>

View file

@ -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()
}

View file

@ -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<android.location.LocationManager>()
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())) }
}
}

View file

@ -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<LocationManager>()
val bluetoothManager = if (bluetoothLeSystemFeature) getSystemService<BluetoothManager>() 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
)
}

View file

@ -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<TextView>(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<TextView>(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)
}
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#2a2931" />
<corners android:radius="20dp" />
</shape>

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingHorizontal="20dp"
android:paddingTop="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/location_settings_dialog_message_title_to_continue"
android:textColor="#e4e1e5"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:text="@string/location_settings_dialog_message_details_start_paragraph"
android:textColor="#e4e1e5"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginStart="30dp"
android:text="@string/location_settings_dialog_message_location_services_gps_and_nlp"
android:textColor="#e4e1e5"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginStart="30dp"
android:text="@string/location_settings_dialog_message_gls_consent"
android:textColor="#e4e1e5"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:text="@string/location_settings_dialog_message_details_end_paragraph"
android:textColor="#e4e1e5"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="24dp"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:id="@+id/location_setting_checker_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/location_settings_dialog_btn_cancel"
android:textColor="#c0c1fa"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/location_setting_checker_sure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="@string/location_settings_dialog_btn_sure"
android:textColor="#c0c1fa"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="pref_location_wifi_mls_enabled_summary">从 Mozilla 位置服务获取基于 Wi-Fi 的位置信息</string>
<string name="pref_location_wifi_learning_enabled_summary">使用 GPS时,在本地存储 Wi-Fi 网络的位置信息</string>
<string name="location_app_last_access_at">最后访问于<xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
<string name="pref_location_cell_mls_enabled_title">向 Mozilla 发出请求</string>
<string name="pref_location_cell_learning_enabled_summary">使用 GPS时,在本地存储移动网络的位置信息</string>
<string name="fragment_location_apps_title">可访问位置信息的应用</string>
<string name="pref_location_app_force_coarse_summary">无视应用的位置权限级别,总是向其提供大致的位置信息。</string>
<string name="pref_location_cell_learning_enabled_title">从 GPS 处学习</string>
<string name="pref_location_wifi_learning_enabled_title">从 GPS 处学习</string>
<string name="pref_location_wifi_moving_enabled_summary">当连接到受支持的热点网络时,从上游热点直接获取 Wi-Fi 位置信息</string>
<string name="prefcat_location_cell_title">基于移动网络的位置信息</string>
<string name="pref_location_wifi_mls_enabled_title">向 Mozilla 发出请求</string>
<string name="pref_location_wifi_moving_enabled_title">向热点发出请求</string>
<string name="pref_location_app_force_coarse_title">总是提供大致的位置</string>
<string name="pref_geocoder_nominatim_enabled_title">使用 Nominatim</string>
<string name="service_name_location">位置信息</string>
<string name="prefcat_location_apps_title">最近访问</string>
<string name="pref_geocoder_nominatim_enabled_summary">使用 OpenStreetMap Nominatim 服务解析地址</string>
<string name="prefcat_location_wifi_title">基于 Wi-Fi 的位置信息</string>
<string name="prefcat_geocoder_title">地址解析器</string>
<string name="pref_location_cell_mls_enabled_summary">从 Mozilla 位置服务获取移动网络信号塔位置</string>
<string name="location_settings_dialog_message_title_to_continue">要继续,请开启设备位置信息功能\n(使用位置信息服务)</string>
<string name="location_settings_dialog_message_details_start_paragraph">您的设备将需要:</string>
<string name="location_settings_dialog_message_location_services_gps_and_nlp">使用GPS、WLAN、移动网络和传感器</string>
<string name="location_settings_dialog_message_gls_consent">使用位置信息服务;在提供该服务的过程中,可能会定期收集位置数据,并以匿名方式使用这类数据,从而提高位置信息的精准度并改善基于地理位置的服务。</string>
<string name="location_settings_dialog_message_details_end_paragraph">有关详细信息,请访问 位置信息设置。</string>
<string name="location_settings_dialog_btn_cancel">不用了</string>
<string name="location_settings_dialog_btn_sure">确定</string>
</resources>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ SPDX-FileCopyrightText: 2023 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="service_name_location">Location</string>
<string name="prefcat_location_apps_title">Recent access</string>
<string name="prefcat_location_wifi_title">Wi-Fi location</string>
<string name="prefcat_location_cell_title">Mobile network location</string>
<string name="prefcat_geocoder_title">Address resolver</string>
<string name="pref_location_wifi_mls_enabled_title">Request from Mozilla</string>
<string name="pref_location_wifi_mls_enabled_summary">Fetch Wi-Fi-based location from Mozilla Location Service.</string>
<string name="pref_location_wifi_moving_enabled_title">Request from Hotspot</string>
<string name="pref_location_wifi_moving_enabled_summary">Fetch Wi-Fi location directly from supported hotspots when connected.</string>
<string name="pref_location_wifi_learning_enabled_title">Remember from GPS</string>
<string name="pref_location_wifi_learning_enabled_summary">Store Wi-Fi locations locally when GPS is used.</string>
<string name="pref_location_cell_mls_enabled_title">Request from Mozilla</string>
<string name="pref_location_cell_mls_enabled_summary">Fetch mobile network cell tower locations from Mozilla Location Service.</string>
<string name="pref_location_cell_learning_enabled_title">Remember from GPS</string>
<string name="pref_location_cell_learning_enabled_summary">Store mobile network locations locally when GPS is used.</string>
<string name="pref_geocoder_nominatim_enabled_title">Use Nominatim</string>
<string name="pref_geocoder_nominatim_enabled_summary">Resolve addresses using OpenStreetMap Nominatim.</string>
<string name="fragment_location_apps_title">Apps with location access</string>
<string name="location_app_last_access_at">Last access: <xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
<string name="pref_location_app_force_coarse_title">Force coarse location</string>
<string name="pref_location_app_force_coarse_summary">Always return coarse locations to this app, ignoring its permission level.</string>
<string name="location_settings_dialog_message_title_to_continue">To continue, turn on device location, which uses location service</string>
<string name="location_settings_dialog_message_details_start_paragraph">Your device will need to:</string>
<string name="location_settings_dialog_message_location_services_gps_and_nlp">Use GPS, Wi‑Fi, cell networks, and sensors</string>
<string name="location_settings_dialog_message_gls_consent">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.</string>
<string name="location_settings_dialog_message_details_end_paragraph">For details, go to the location settings.</string>
<string name="location_settings_dialog_btn_cancel">No,thanks</string>
<string name="location_settings_dialog_btn_sure">OK</string>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AlertThemeSelector" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowBackground">@drawable/custom_dialog_background</item>
<item name="android:windowMinWidthMajor">85%</item>
<item name="android:windowMinWidthMinor">85%</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
</resources>

View file

@ -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<ParcelableGeofence> 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;
}

View file

@ -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<LocationRequest> 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<LocationRequest> 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<LocationRequest> requests = new ArrayList<LocationRequest>();
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<LocationRequest> 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<LocationSettingsRequest> CREATOR = findCreator(LocationSettingsRequest.class);
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
}

View file

@ -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)}.
* <p>
* 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.
* <p>
* The current location settings states can be accessed via {@link #getLocationSettingsStates()}. See {@link LocationSettingsStates} for more details.
*/
public class LocationSettingsResponse extends Response<LocationSettingsResult> {
/**
* Retrieves the location settings states.
*/
@Nullable
public LocationSettingsStates getLocationSettingsStates() {
return getResult().getLocationSettingsStates();
}
@Hide
public LocationSettingsResponse(@NonNull LocationSettingsResult result) {
super(result);
}
}

View file

@ -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.
* <p>
* 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.
* <p>
* 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<LocationSettingsResult> CREATOR = findCreator(LocationSettingsResult.class);
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CREATOR.writeToParcel(this, dest, flags);
}
}

View file

@ -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.
* <p>
* 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.
* <p>
* 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<LocationSettingsStates> 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";
}

View file

@ -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.
* <p>
* 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<Api.ApiOptions.NoOptions> {
/**
* 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<LocationSettingsResponse> 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.
* <p>
* 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<Boolean> isGoogleLocationAccuracyEnabled();
}

View file

@ -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<Api.ApiOptions.NoOptions> implements SettingsClient {
public SettingsClientImpl(Context context) {
super(context, LocationServices.API);
}
@Override
public Task<LocationSettingsResponse> checkLocationSettings(LocationSettingsRequest locationSettingsRequest) {
return scheduleTask((PendingGoogleApiCall<LocationSettingsResponse, LocationClientImpl>) (client, completionSource) -> client.getServiceInterface().requestLocationSettingsDialog(locationSettingsRequest, new ISettingsCallbacks.Stub() {
@Override
public void onLocationSettingsResult(LocationSettingsResult result) {
completionSource.setResult(new LocationSettingsResponse(result));
}
}, null));
}
@Override
public Task<Boolean> isGoogleLocationAccuracyEnabled() {
return Tasks.forResult(true); // TODO
}
}