Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,18 @@ object SettingsContract {
)
}

object Wearable {
const val ID = "wearable"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID"

const val AUTO_ACCEPT_TOS = "wearable_auto_accept_tos"

val PROJECTION = arrayOf(
AUTO_ACCEPT_TOS
)
}

private fun <T> withoutCallingIdentity(f: () -> T): T {
val identity = Binder.clearCallingIdentity()
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.microg.gms.settings.SettingsContract.Location
import org.microg.gms.settings.SettingsContract.Profile
import org.microg.gms.settings.SettingsContract.SafetyNet
import org.microg.gms.settings.SettingsContract.Vending
import org.microg.gms.settings.SettingsContract.Wearable
import org.microg.gms.settings.SettingsContract.WorkProfile
import org.microg.gms.settings.SettingsContract.getAuthority
import java.io.File
Expand Down Expand Up @@ -85,6 +86,7 @@ class SettingsProvider : ContentProvider() {
Vending.ID -> queryVending(projection ?: Vending.PROJECTION)
WorkProfile.ID -> queryWorkProfile(projection ?: WorkProfile.PROJECTION)
GameProfile.ID -> queryGameProfile(projection ?: GameProfile.PROJECTION)
Wearable.ID -> queryWearable(projection ?: Wearable.PROJECTION)
else -> null
}

Expand All @@ -108,6 +110,7 @@ class SettingsProvider : ContentProvider() {
Vending.ID -> updateVending(values)
WorkProfile.ID -> updateWorkProfile(values)
GameProfile.ID -> updateGameProfile(values)
Wearable.ID -> updateWearable(values)
else -> return 0
}
return 1
Expand Down Expand Up @@ -434,6 +437,25 @@ class SettingsProvider : ContentProvider() {
editor.apply()
}

private fun queryWearable(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Wearable.AUTO_ACCEPT_TOS -> getSettingsBoolean(key, false)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}

private fun updateWearable(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Wearable.AUTO_ACCEPT_TOS -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}

private fun MatrixCursor.addRow(
p: Array<out String>,
valueGetter: (String) -> Any?
Expand Down
3 changes: 3 additions & 0 deletions play-services-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// Default to debug signing so the APK is installable out of the box.
// Override signingConfig in user.gradle for production/release builds.
signingConfig signingConfigs.debug
}
}

Expand Down
25 changes: 23 additions & 2 deletions play-services-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,18 @@

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<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_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission
android:name="android.permission.MEDIA_CONTENT_CONTROL"
tools:ignore="ProtectedPermissions" />

<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Expand Down Expand Up @@ -265,7 +273,9 @@
</intent-filter>
</service>

<service android:name="org.microg.gms.wearable.location.WearableLocationService">
<service
android:name="org.microg.gms.wearable.location.WearableLocationService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data
Expand Down Expand Up @@ -456,12 +466,23 @@

<!-- Wearable -->

<service android:name="org.microg.gms.wearable.WearableService">
<service
android:name="org.microg.gms.wearable.WearableService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND" />
</intent-filter>
</service>

<service
android:name="org.microg.gms.wearable.notification.WearableNotificationService"
android:exported="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>

<activity
android:name="com.google.android.gms.wearable.consent.TermsOfServiceActivity"
android:process=":ui"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,40 @@

package com.google.android.gms.wearable.consent

import android.app.AlertDialog
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.R
import org.microg.gms.wearable.WearablePreferences

class TermsOfServiceActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResult(RESULT_CANCELED)
finish()

if (WearablePreferences.isAutoAcceptTosEnabled(this)) {
// User has opted-in to auto-accept; proceed immediately.
setResult(RESULT_OK)
finish()
return
}

// Show an explicit dialog so the user can make an informed choice.
AlertDialog.Builder(this)
.setTitle(R.string.wearable_tos_dialog_title)
.setMessage(R.string.wearable_tos_dialog_message)
.setPositiveButton(R.string.wearable_tos_accept) { _, _ ->
setResult(RESULT_OK)
finish()
}
.setNegativeButton(R.string.wearable_tos_decline) { _, _ ->
setResult(RESULT_CANCELED)
finish()
}
.setOnCancelListener {
setResult(RESULT_CANCELED)
finish()
}
.show()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class SettingsFragment : ResourceSettingsFragment() {
findNavController().navigate(requireContext(), R.id.openWorkProfileSettings)
true
}
findPreference<Preference>(PREF_WEARABLE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
findNavController().navigate(requireContext(), R.id.openWearableSettings)
true
}

findPreference<Preference>(PREF_ABOUT)!!.apply {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
Expand Down Expand Up @@ -139,6 +143,7 @@ class SettingsFragment : ResourceSettingsFragment() {
const val PREF_VENDING = "pref_vending"
const val PREF_WORK_PROFILE = "pref_work_profile"
const val PREF_ACCOUNTS = "pref_accounts"
const val PREF_WEARABLE = "pref_wearable"
}

init {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package org.microg.gms.ui

import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import com.google.android.gms.R
import org.microg.gms.wearable.WearablePreferences

class WearableFragment : PreferenceFragmentCompat() {
private lateinit var autoAcceptTos: TwoStatePreference

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_wearable)

autoAcceptTos = preferenceScreen.findPreference(PREF_AUTO_ACCEPT_TOS)!!
autoAcceptTos.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
if (newValue is Boolean) {
WearablePreferences.setAutoAcceptTosEnabled(appContext, newValue)
}
updateContent()
}
true
}
}

override fun onResume() {
super.onResume()
updateContent()
}

private fun updateContent() {
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
autoAcceptTos.isChecked = WearablePreferences.isAutoAcceptTosEnabled(appContext)
}
}

companion object {
const val PREF_AUTO_ACCEPT_TOS = "wearable_auto_accept_tos"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package org.microg.gms.wearable

import android.content.Context
import org.microg.gms.settings.SettingsContract

object WearablePreferences {
@JvmStatic
fun isAutoAcceptTosEnabled(context: Context): Boolean {
val projection = arrayOf(SettingsContract.Wearable.AUTO_ACCEPT_TOS)
return SettingsContract.getSettings(context, SettingsContract.Wearable.getContentUri(context), projection) { c ->
c.getInt(0) != 0
}
}

@JvmStatic
fun setAutoAcceptTosEnabled(context: Context, enabled: Boolean) {
SettingsContract.setSettings(context, SettingsContract.Wearable.getContentUri(context)) {
put(SettingsContract.Wearable.AUTO_ACCEPT_TOS, enabled)
}
}
}
Loading