Skip to content

Commit 539dd67

Browse files
committed
Location: Add UI to configure custom location service URL
1 parent 7b6e7d1 commit 539dd67

File tree

10 files changed

+126
-51
lines changed

10 files changed

+126
-51
lines changed

play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/UserConsentPromptActivity.kt

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,16 @@
66
package org.microg.gms.auth.phone
77

88
import android.annotation.TargetApi
9-
import android.app.Activity
10-
import android.app.Dialog
119
import android.content.Intent
12-
import android.content.pm.PackageManager
13-
import android.net.Uri
1410
import android.os.*
15-
import android.telephony.SmsMessage
1611
import android.text.Html
17-
import android.text.TextUtils
18-
import android.util.Log
1912
import android.view.Gravity
2013
import android.view.ViewGroup.LayoutParams
2114
import android.widget.Button
2215
import android.widget.TextView
23-
import androidx.appcompat.app.AlertDialog
2416
import androidx.appcompat.app.AppCompatActivity
25-
import androidx.core.os.bundleOf
2617
import com.google.android.gms.auth.api.phone.SmsRetriever
18+
import org.microg.gms.ui.buildAlertDialog
2719
import org.microg.gms.utils.getApplicationLabel
2820

2921
private const val TAG = "UserConsentPrompt"
@@ -53,10 +45,10 @@ class UserConsentPromptActivity : AppCompatActivity() {
5345
@TargetApi(16)
5446
private fun showConsentDialog(callingPackage: String, message: String) {
5547
val view = layoutInflater.inflate(R.layout.dialog_sms_user_consent, null)
56-
val dialog = AlertDialog.Builder(this).apply {
57-
setCancelable(false)
58-
setView(view)
59-
}.create()
48+
val dialog = buildAlertDialog()
49+
.setCancelable(false)
50+
.setView(view)
51+
.create()
6052
val appName = packageManager.getApplicationLabel(callingPackage)
6153

6254
view.findViewById<TextView>(android.R.id.title).text = Html.fromHtml(getString(R.string.sms_user_consent_title, Html.escapeHtml(appName)))

play-services-base/core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ class SettingsProvider : ContentProvider() {
336336
Location.CELL_ICHNAEA -> editor.putBoolean(key, value as Boolean)
337337
Location.CELL_LEARNING -> editor.putBoolean(key, value as Boolean)
338338
Location.GEOCODER_NOMINATIM -> editor.putBoolean(key, value as Boolean)
339-
Location.ICHNAEA_ENDPOINT -> editor.putString(key, value as String)
339+
Location.ICHNAEA_ENDPOINT -> (value as String).let { if (it.isBlank()) editor.remove(key) else editor.putString(key, it) }
340340
else -> throw IllegalArgumentException("Unknown key: $key")
341341
}
342342
}

play-services-base/core/src/main/kotlin/org/microg/gms/ui/Utils.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import android.view.View
1717
import androidx.annotation.AttrRes
1818
import androidx.annotation.ColorInt
1919
import androidx.annotation.IdRes
20+
import androidx.appcompat.app.AlertDialog
2021
import androidx.core.content.ContextCompat
2122
import androidx.databinding.BindingAdapter
2223
import androidx.navigation.NavController
2324
import androidx.navigation.navOptions
2425
import androidx.navigation.ui.R
26+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
2527

2628
fun PackageManager.getApplicationInfoIfExists(packageName: String?, flags: Int = 0): ApplicationInfo? = packageName?.let {
2729
try {
@@ -57,6 +59,12 @@ val Context.systemAnimationsEnabled: Boolean
5759
return duration != 0f && transition != 0f
5860
}
5961

62+
fun Context.buildAlertDialog() = try {
63+
// Try material design first
64+
MaterialAlertDialogBuilder(this)
65+
} catch (e: Exception) {
66+
AlertDialog.Builder(this)
67+
}
6068

6169
@ColorInt
6270
fun Context.resolveColor(@AttrRes resid: Int): Int? {

play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ class PushNotificationAppFragment : PreferenceFragmentCompat() {
7676
private fun showUnregisterConfirm(unregisterConfirmDesc: Int) {
7777
val pm = requireContext().packageManager
7878
val applicationInfo = pm.getApplicationInfoIfExists(packageName)
79-
AlertDialog.Builder(requireContext())
79+
requireContext().buildAlertDialog()
8080
.setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm)
8181
?: packageName))
8282
.setMessage(unregisterConfirmDesc)
8383
.setPositiveButton(android.R.string.yes) { _, _ -> unregister() }
84-
.setNegativeButton(android.R.string.no) { _, _ -> }.show()
84+
.setNegativeButton(android.R.string.no) { _, _ -> }
85+
.show()
8586
}
8687

8788
private fun unregister() {

play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/NetworkLocationService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
438438
writer.println("Last cell location: $lastCellLocation${if (lastCellLocation == lastLocation) " (active)" else ""}")
439439
writer.println("Wifi settings: ichnaea=${settings.wifiIchnaea} moving=${settings.wifiMoving} learn=${settings.wifiLearning}")
440440
writer.println("Cell settings: ichnaea=${settings.cellIchnaea} learn=${settings.cellLearning}")
441-
writer.println("Ichnaea settings: endpoint=${settings.ichneaeEndpoint}")
441+
writer.println("Ichnaea settings: endpoint=${settings.ichneaeEndpoint} contribute=${settings.ichnaeaContribute}")
442442
writer.println("Wifi scan cache size=${wifiScanCache.size()} hits=${wifiScanCache.hitCount()} miss=${wifiScanCache.missCount()} puts=${wifiScanCache.putCount()} evicts=${wifiScanCache.evictionCount()}")
443443
writer.println("GPS location buffer size=${gpsLocationBuffer.size} first=${gpsLocationBuffer.firstOrNull()?.elapsedMillis?.formatRealtime()} last=${gpsLocationBuffer.lastOrNull()?.elapsedMillis?.formatRealtime()}")
444444
cache.dump(writer)

play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.google.android.gms.location.LocationRequest
2525
import com.google.android.gms.location.LocationSettingsRequest
2626
import com.google.android.material.dialog.MaterialAlertDialogBuilder
2727
import org.microg.gms.location.core.R
28+
import org.microg.gms.ui.buildAlertDialog
2829

2930
const val ACTION_LOCATION_SETTINGS_CHECKER = "com.google.android.gms.location.settings.CHECK_SETTINGS"
3031
const val EXTRA_ORIGINAL_PACKAGE_NAME = "originalPackageName"
@@ -101,16 +102,11 @@ class LocationSettingsCheckerActivity : Activity(), DialogInterface.OnCancelList
101102

102103
private fun showDialog() {
103104

104-
val alertDialog = try {
105-
// Try material design first
106-
MaterialAlertDialogBuilder(this)
107-
} catch (e: Exception) {
108-
AlertDialog.Builder(this)
109-
}
110-
.setOnCancelListener(this)
111-
.setPositiveButton(R.string.location_settings_dialog_btn_sure, this)
112-
.setNegativeButton(R.string.location_settings_dialog_btn_cancel, this)
113-
.create()
105+
val alertDialog = buildAlertDialog()
106+
.setOnCancelListener(this)
107+
.setPositiveButton(R.string.location_settings_dialog_btn_sure, this)
108+
.setNegativeButton(R.string.location_settings_dialog_btn_cancel, this)
109+
.create()
114110
alertDialog.setCanceledOnTouchOutside(false)
115111

116112
val view = layoutInflater.inflate(R.layout.location_settings_dialog, null)

play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/LocationPreferencesFragment.kt

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

66
package org.microg.gms.location.ui
77

8+
import android.content.DialogInterface
89
import android.location.LocationManager
910
import android.os.Build.VERSION.SDK_INT
1011
import android.os.Bundle
12+
import android.view.Menu
13+
import android.view.MenuInflater
14+
import android.view.MenuItem
15+
import android.widget.EditText
16+
import androidx.appcompat.app.AlertDialog
1117
import androidx.core.content.getSystemService
1218
import androidx.core.os.bundleOf
1319
import androidx.lifecycle.lifecycleScope
@@ -16,6 +22,7 @@ import androidx.preference.Preference
1622
import androidx.preference.PreferenceCategory
1723
import androidx.preference.PreferenceFragmentCompat
1824
import androidx.preference.TwoStatePreference
25+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
1926
import kotlinx.coroutines.Dispatchers
2027
import kotlinx.coroutines.withContext
2128
import org.microg.gms.location.LocationSettings
@@ -24,6 +31,7 @@ import org.microg.gms.location.hasIchnaeaLocationServiceSupport
2431
import org.microg.gms.location.hasNetworkLocationServiceBuiltIn
2532
import org.microg.gms.location.manager.LocationAppsDatabase
2633
import org.microg.gms.ui.AppIconPreference
34+
import org.microg.gms.ui.buildAlertDialog
2735
import org.microg.gms.ui.getApplicationInfoIfExists
2836
import org.microg.gms.ui.navigate
2937

@@ -40,6 +48,39 @@ class LocationPreferencesFragment : PreferenceFragmentCompat() {
4048
private lateinit var nominatim: TwoStatePreference
4149
private lateinit var database: LocationAppsDatabase
4250

51+
init {
52+
setHasOptionsMenu(true)
53+
}
54+
55+
companion object {
56+
private const val MENU_ICHNAEA_URL = Menu.FIRST
57+
}
58+
59+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
60+
if (requireContext().hasIchnaeaLocationServiceSupport()) {
61+
menu.add(0, MENU_ICHNAEA_URL, 0, R.string.pref_location_custom_url_title)
62+
}
63+
super.onCreateOptionsMenu(menu, inflater)
64+
}
65+
66+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
67+
if (item.itemId == MENU_ICHNAEA_URL) {
68+
val view = layoutInflater.inflate(R.layout.preference_location_custom_url, null)
69+
view.findViewById<EditText>(android.R.id.edit).setText(LocationSettings(requireContext()).ichneaeEndpoint)
70+
requireContext().buildAlertDialog()
71+
.setTitle(R.string.pref_location_custom_url_title)
72+
.setPositiveButton(android.R.string.ok) { _, _ ->
73+
LocationSettings(requireContext()).ichneaeEndpoint = view.findViewById<EditText>(android.R.id.edit).text.toString()
74+
}
75+
.setNegativeButton(android.R.string.cancel) { _, _ -> }
76+
.setNeutralButton(R.string.pref_location_custom_url_reset) { _, _ -> LocationSettings(requireContext()).ichneaeEndpoint = "" }
77+
.setView(view)
78+
.show()
79+
return true
80+
}
81+
return super.onOptionsItemSelected(item)
82+
}
83+
4384
override fun onCreate(savedInstanceState: Bundle?) {
4485
super.onCreate(savedInstanceState)
4586
database = LocationAppsDatabase(requireContext())
@@ -63,30 +104,18 @@ class LocationPreferencesFragment : PreferenceFragmentCompat() {
63104
findNavController().navigate(requireContext(), R.id.openAllLocationApps)
64105
true
65106
}
66-
wifiIchnaea.setOnPreferenceChangeListener { _, newValue ->
67-
LocationSettings(requireContext()).wifiIchnaea = newValue as Boolean
68-
true
69-
}
70-
wifiMoving.setOnPreferenceChangeListener { _, newValue ->
71-
LocationSettings(requireContext()).wifiMoving = newValue as Boolean
72-
true
73-
}
74-
wifiLearning.setOnPreferenceChangeListener { _, newValue ->
75-
LocationSettings(requireContext()).wifiLearning = newValue as Boolean
76-
true
77-
}
78-
cellIchnaea.setOnPreferenceChangeListener { _, newValue ->
79-
LocationSettings(requireContext()).cellIchnaea = newValue as Boolean
80-
true
81-
}
82-
cellLearning.setOnPreferenceChangeListener { _, newValue ->
83-
LocationSettings(requireContext()).cellLearning = newValue as Boolean
84-
true
85-
}
86-
nominatim.setOnPreferenceChangeListener { _, newValue ->
87-
LocationSettings(requireContext()).geocoderNominatim = newValue as Boolean
88-
true
107+
fun configureChangeListener(preference: TwoStatePreference, listener: (Boolean) -> Unit) {
108+
preference.setOnPreferenceChangeListener { _, newValue ->
109+
listener(newValue as Boolean)
110+
true
111+
}
89112
}
113+
configureChangeListener(wifiIchnaea) { LocationSettings(requireContext()).wifiIchnaea = it }
114+
configureChangeListener(wifiMoving) { LocationSettings(requireContext()).wifiMoving = it }
115+
configureChangeListener(wifiLearning) { LocationSettings(requireContext()).wifiLearning = it }
116+
configureChangeListener(cellIchnaea) { LocationSettings(requireContext()).cellIchnaea = it }
117+
configureChangeListener(cellLearning) { LocationSettings(requireContext()).cellLearning = it }
118+
configureChangeListener(nominatim) { LocationSettings(requireContext()).geocoderNominatim = it }
90119

91120
networkProviderCategory.isVisible = requireContext().hasNetworkLocationServiceBuiltIn()
92121
wifiIchnaea.isVisible = requireContext().hasIchnaeaLocationServiceSupport()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ SPDX-FileCopyrightText: 2024 microG Project Team
3+
~ SPDX-License-Identifier: Apache-2.0
4+
-->
5+
6+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
7+
xmlns:app="http://schemas.android.com/apk/res-auto"
8+
android:orientation="vertical"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent"
11+
android:layout_weight="1"
12+
android:paddingLeft="24dp"
13+
android:paddingRight="24dp"
14+
android:fillViewport="true">
15+
16+
<TextView
17+
android:layout_width="match_parent"
18+
android:layout_height="wrap_content"
19+
android:layout_marginTop="16dp"
20+
android:text="@string/pref_location_custom_url_summary" />
21+
22+
<TextView
23+
android:layout_width="match_parent"
24+
android:layout_height="wrap_content"
25+
android:layout_marginTop="16dp"
26+
android:text="@string/pref_location_custom_url_details" />
27+
28+
<com.google.android.material.textfield.TextInputLayout
29+
android:layout_width="match_parent"
30+
android:layout_height="wrap_content"
31+
android:layout_marginTop="16dp"
32+
android:hint="@string/pref_location_custom_url_input_hint"
33+
app:placeholderText="https://example.com/?key=example">
34+
35+
<requestFocus />
36+
37+
<com.google.android.material.textfield.TextInputEditText
38+
android:id="@android:id/edit"
39+
android:layout_width="match_parent"
40+
android:layout_height="wrap_content" />
41+
42+
</com.google.android.material.textfield.TextInputLayout>
43+
</LinearLayout>

play-services-location/core/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,9 @@
3737
<string name="location_settings_dialog_btn_cancel">No thanks</string>
3838
<string name="location_settings_dialog_btn_sure">OK</string>
3939

40+
<string name="pref_location_custom_url_title">Configure service URL</string>
41+
<string name="pref_location_custom_url_reset">Reset</string>
42+
<string name="pref_location_custom_url_summary">This allows setting a custom service URL. Invalid values can result in location services being unresponsive or entirely unavailable.</string>
43+
<string name="pref_location_custom_url_details">The /v1/geolocate path is automatically appended. If the location provider requires a key, it can be appended as a query parameter to the root URL.</string>
44+
<string name="pref_location_custom_url_input_hint">Custom service URL</string>
4045
</resources>

play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsRpisFragment.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.preference.PreferenceFragmentCompat
1818
import androidx.recyclerview.widget.RecyclerView
1919
import org.microg.gms.nearby.core.R
2020
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
21+
import org.microg.gms.ui.buildAlertDialog
2122

2223
@TargetApi(21)
2324
class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
@@ -49,7 +50,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
4950
deleteAll = preferenceScreen.findPreference("pref_exposure_rpi_delete_all") ?: deleteAll
5051
exportDb = preferenceScreen.findPreference("pref_exposure_export_database") ?: exportDb
5152
deleteAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {
52-
AlertDialog.Builder(requireContext())
53+
requireContext().buildAlertDialog()
5354
.setTitle(R.string.pref_exposure_rpi_delete_all_title)
5455
.setView(R.layout.exposure_notifications_confirm_delete)
5556
.setPositiveButton(R.string.pref_exposure_rpi_delete_all_warning_confirm_button) { _, _ ->

0 commit comments

Comments
 (0)