Skip to content
Merged
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
18 changes: 9 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ buildscript {

desugar_version = '2.1.5'

firebase_version = '33.12.0'
firebase_version = '33.13.0'

activity_version = '1.10.1'
appcompat_version = '1.7.0'
constraintlayout_version = '2.2.1'
core_version = '1.16.0'
fragment_version = '1.8.6'
lifecycle_version = '2.8.7'
lifecycle_version = '2.9.0'
preference_version = '1.2.1'
recyclerview_version = '1.4.0'
coresplash_version = '1.0.1'
work_version = '2.10.0'
navigation_version = '2.8.9'
datastore_version = '1.1.4'
work_version = '2.10.1'
navigation_version = '2.9.0'
datastore_version = '1.1.7'

test_core_version = '1.6.1'
test_runner_version = '1.6.2'
Expand All @@ -35,15 +35,15 @@ buildscript {

material_version = '1.12.0'

compose_bom_version = '2025.04.00'
compose_bom_version = '2025.05.00'
compose_compiler_version = '1.5.15'
wear_compose_version = '1.4.1'
wear_tiles_version = '1.4.1'
wear_watchface_version = '1.2.1'
horologist_version = '0.6.23'
accompanist_version = '0.37.2'
accompanist_version = '0.37.3'

gson_version = '2.13.0'
gson_version = '2.13.1'
timber_version = '5.0.1'

// Shizuku
Expand All @@ -57,7 +57,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:8.9.1'
classpath 'com.android.tools.build:gradle:8.10.0'
classpath 'com.google.gms:google-services:4.4.2'
classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Expand Down
14 changes: 10 additions & 4 deletions docs/settings-helper.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ permalink: /settings-helper

Companion app for SimpleWear

Latest version: [SimpleWear Settings v1.3.0]({{ site.github.repository_url}}/releases/download/v1.16.0_beta/wearsettings-release-1.3.0.apk)
Latest version: [SimpleWear Settings v1.3.1]({{
site.github.repository_url}}/releases/download/v1.16.1_release/wearsettings-release-1.3.1.apk)

Previous version: [SimpleWear Settings v1.2.0]({{ site.github.repository_url}}/releases/download/v1.15.2-release/wearsettings-release-1.2.0.apk)
Previous version: [SimpleWear Settings v1.3.0]({{
site.github.repository_url}}/releases/download/v1.16.0_beta/wearsettings-release-1.3.0.apk)

## WiFi and Location Toggle

Expand All @@ -23,8 +25,12 @@ If you are using Android 10 and above, and want to toggle **Wi-Fi** settings or

## Mobile Data

SimpleWear is unable to toggle mobile data without system permissions. [Root access](./root-access) or for unrooted devices, [Shizuku](https://github.com/RikkaApps/Shizuku) can be used. Please follow the instructions in app to start.
SimpleWear is unable to toggle mobile data without system permissions. [Root access](./root-access)
or for unrooted devices, [Shizuku](https://github.com/RikkaApps/Shizuku) can be used. Please follow
the instructions in app to start.

## Bluetooth

As of Android 13 (or T), non-system apps are no longer allowed to toggle Bluetooth on or off. This helper app is needed in order to allow SimpleWear to toggle Bluetooth . The helper app is built for an older version of Android which allows it to be able to toggle Bluetooth.
As of Android 13 (or T), non-system apps are no longer allowed to toggle Bluetooth on or off. This
helper app is needed in order to allow SimpleWear to toggle Bluetooth. The helper app is built for
an older version of Android which allows it to be able to toggle Bluetooth.
4 changes: 2 additions & 2 deletions mobile/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ android {
targetSdkVersion rootProject.targetSdkVersion
// NOTE: Version Code Format [TargetSDK, Version Name, Build Number, Variant Code (Android: 0, WearOS: 1)]
// NOTE: update SUPPORTED_VERSION_CODE if needed
versionCode 341916040
versionName "1.16.0"
versionCode 341916050
versionName "1.16.1"

vectorDrawables.useSupportLibrary = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,18 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import java.io.BufferedWriter
import java.io.OutputStreamWriter
import java.nio.ByteBuffer
import java.util.Collections
import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.resume

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class WearableManager(private val mContext: Context) : OnCapabilityChangedListener,
RemoteActionReceiver.IResultReceiver {
class WearableManager(private val mContext: Context) : OnCapabilityChangedListener {
init {
init()
}
Expand All @@ -102,22 +104,16 @@ class WearableManager(private val mContext: Context) : OnCapabilityChangedListen
private lateinit var mCapabilityClient: CapabilityClient
private var mWearNodesWithApp: Collection<Node>? = null

private lateinit var mResultReceiver: RemoteActionReceiver
private var mPackageValidator = PackageValidator(mContext)

private fun init() {
mCapabilityClient = Wearable.getCapabilityClient(mContext)
mCapabilityClient.addListener(this, WearableHelper.CAPABILITY_WEAR_APP)

mResultReceiver = RemoteActionReceiver().apply {
resultReceiver = this@WearableManager
}
}

fun unregister() {
scope.cancel()
mCapabilityClient.removeListener(this)
mResultReceiver.resultReceiver = null
}

suspend fun isWearNodesAvailable(): Boolean {
Expand Down Expand Up @@ -1102,26 +1098,58 @@ class WearableManager(private val mContext: Context) : OnCapabilityChangedListen
}
}

private fun performRemoteAction(action: Action): ActionStatus {
private suspend fun performRemoteAction(action: Action): ActionStatus {
return try {
if (mPackageValidator.isKnownCaller(WearSettingsHelper.getPackageName())) {
mContext.startService(
Intent(ACTION_PERFORMACTION).apply {
component = WearSettingsHelper.getSettingsServiceComponent()
putExtra(
EXTRA_ACTION_DATA,
action.toRemoteAction(mResultReceiver)
)
putExtra(
EXTRA_ACTION_CALLINGPKG,
mContext.packageName
)
suspendCancellableCoroutine { continuation ->
val remoteActionReceiver = RemoteActionReceiver().apply {
resultReceiver = object : RemoteActionReceiver.IResultReceiver {
override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
if (resultCode == Activity.RESULT_OK) {
if (continuation.isActive) {
continuation.resume(ActionStatus.SUCCESS)
}
} else {
var resultStatus = ActionStatus.REMOTE_FAILURE

if (resultData.containsKey(EXTRA_ACTION_ERROR)) {
Logger.writeLine(
Log.ERROR,
"Error executing remote action; Error: %s",
resultData.getString(EXTRA_ACTION_ERROR)
)
} else if (resultData.containsKey(EXTRA_ACTION_DATA)) {
val actionData = resultData.getString(EXTRA_ACTION_DATA)
val resultAction =
JSONParser.deserializer(actionData, Action::class.java)
resultStatus = resultAction?.actionStatus ?: resultStatus
}

if (continuation.isActive) {
continuation.resume(resultStatus)
}
}
}
}
)
ActionStatus.UNKNOWN
} else {
throw IllegalStateException("Package: ${WearSettingsHelper.getPackageName()} has invalid certificate")
}

continuation.invokeOnCancellation {
remoteActionReceiver.resultReceiver = null
}

if (mPackageValidator.isKnownCaller(WearSettingsHelper.getPackageName())) {
mContext.startService(
Intent(ACTION_PERFORMACTION).apply {
component = WearSettingsHelper.getSettingsServiceComponent()
putExtra(EXTRA_ACTION_DATA, action.toRemoteAction(remoteActionReceiver))
putExtra(EXTRA_ACTION_CALLINGPKG, mContext.packageName)
}
)
} else {
throw IllegalStateException("Package: ${WearSettingsHelper.getPackageName()} has invalid certificate")
}
}
} catch (ce: CancellationException) {
ActionStatus.UNKNOWN
} catch (ise: IllegalStateException) {
// Likely background service restriction
Logger.writeLine(Log.ERROR, ise)
Expand All @@ -1131,31 +1159,4 @@ class WearableManager(private val mContext: Context) : OnCapabilityChangedListen
ActionStatus.REMOTE_FAILURE
}
}

override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
if (resultData.containsKey(EXTRA_ACTION_ERROR)) {
Logger.writeLine(
Log.ERROR,
"Error executing remote action; Error: %s",
resultData.getString(EXTRA_ACTION_ERROR)
)
}
if (resultCode == Activity.RESULT_CANCELED && resultData.containsKey(EXTRA_ACTION_DATA)) {
// Check for remote failure
val actionData = resultData.getString(EXTRA_ACTION_DATA)
val action = JSONParser.deserializer(actionData, Action::class.java)
if (action?.actionStatus == ActionStatus.REMOTE_FAILURE ||
action?.actionStatus == ActionStatus.REMOTE_PERMISSION_DENIED
) {
scope.launch {
sendMessage(
null,
WearableHelper.ActionsPath,
actionData?.stringToBytes()
)
WearSettingsHelper.launchWearSettings()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.thewizrd.shared_resources.utils.Logger
object WearSettingsHelper {
// Link to Play Store listing
const val PACKAGE_NAME = "com.thewizrd.wearsettings"
private const val SUPPORTED_VERSION_CODE: Long = 1030000
private const val SUPPORTED_VERSION_CODE: Long = 1030002

fun getPackageName(): String {
var packageName = PACKAGE_NAME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object WearableHelper {
// Link to Play Store listing
private const val PLAY_STORE_APP_URI = "market://details?id=com.thewizrd.simplewear"

private const val SUPPORTED_VERSION_CODE: Long = 341916000
private const val SUPPORTED_VERSION_CODE: Long = 341916050

fun getPlayStoreURI(): Uri = Uri.parse(PLAY_STORE_APP_URI)

Expand Down
4 changes: 2 additions & 2 deletions wear/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
minSdkVersion 26
targetSdkVersion rootProject.targetSdkVersion
// NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code (Android: 0, WearOS: 1)
versionCode 341916041
versionName "1.16.0"
versionCode 341916051
versionName "1.16.1"

vectorDrawables.useSupportLibrary = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class DashboardViewModel(app: Application) : WearableListenerViewModel(app) {

requestAction(jsonData)

val timer: CountDownTimer = object : CountDownTimer(3000, 500) {
val timer: CountDownTimer = object : CountDownTimer(5000, 500) {
override fun onTick(millisUntilFinished: Long) {}

override fun onFinish() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ValueActionViewModel(app: Application) : WearableListenerViewModel(app) {

viewModelScope.launch {
timer?.cancel()
timer = object : CountDownTimer(3000, 500) {
timer = object : CountDownTimer(5000, 500) {
override fun onTick(millisUntilFinished: Long) {}

override fun onFinish() {
Expand Down
4 changes: 2 additions & 2 deletions wearsettings/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
//noinspection ExpiredTargetSdkVersion
targetSdk 28
// NOTE: update SUPPORTED_VERSION_CODE if needed
versionCode 1030001
versionName "1.3.0"
versionCode 1030002
versionName "1.3.1"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import com.thewizrd.shared_resources.utils.Logger
import com.thewizrd.wearsettings.root.RootHelper
import com.thewizrd.wearsettings.shizuku.ShizukuUtils
import com.thewizrd.wearsettings.shizuku.grantSecureSettingsPermission
import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
import com.thewizrd.wearsettings.Settings as SettingsHelper
Expand All @@ -29,7 +28,7 @@ object LocationAction {

return if (checkSecureSettingsPermission(context)) {
setLocationState(context, state)
} else if (Shizuku.pingBinder()) {
} else if (ShizukuUtils.isRunning(context)) {
context.grantSecureSettingsPermission()
setLocationState(context, state)
} else if (SettingsHelper.isRootAccessEnabled() && RootHelper.isRootEnabled()) {
Expand All @@ -38,7 +37,7 @@ object LocationAction {
ActionStatus.REMOTE_PERMISSION_DENIED
}
} else if (action is ToggleAction) {
return if (Shizuku.pingBinder()) {
return if (ShizukuUtils.isRunning(context)) {
setLocationEnabledShizuku(context, action.isEnabled)
} else if (checkSecureSettingsPermission(context)) {
setLocationEnabled(context, action.isEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import com.thewizrd.shared_resources.actions.ActionStatus
import com.thewizrd.shared_resources.actions.NormalAction
import com.thewizrd.shared_resources.utils.Logger
import com.thewizrd.wearsettings.root.RootHelper
import com.thewizrd.wearsettings.shizuku.ShizukuUtils
import com.topjohnwu.superuser.Shell
import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
import com.thewizrd.wearsettings.Settings as SettingsHelper

object LockScreenAction {
fun executeAction(context: Context, action: Action): ActionStatus {
if (action is NormalAction) {
return if (Shizuku.pingBinder()) {
return if (ShizukuUtils.isRunning(context)) {
lockScreenShizuku(context)
} else if (SettingsHelper.isRootAccessEnabled() && RootHelper.isRootEnabled()) {
lockScreenRoot()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import com.thewizrd.shared_resources.actions.ActionStatus
import com.thewizrd.shared_resources.actions.ToggleAction
import com.thewizrd.shared_resources.utils.Logger
import com.thewizrd.wearsettings.root.RootHelper
import com.thewizrd.wearsettings.shizuku.ShizukuUtils
import com.topjohnwu.superuser.Shell
import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
import com.thewizrd.wearsettings.Settings as SettingsHelper

object MobileDataAction {
fun executeAction(context: Context, action: Action): ActionStatus {
if (action is ToggleAction) {
return if (Shizuku.pingBinder()) {
return if (ShizukuUtils.isRunning(context)) {
setMobileDataEnabledShizuku(context, action.isEnabled)
} else if (SettingsHelper.isRootAccessEnabled() && RootHelper.isRootEnabled()) {
setMobileDataEnabledRoot(action.isEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import com.thewizrd.shared_resources.actions.ToggleAction
import com.thewizrd.shared_resources.utils.Logger
import com.thewizrd.wearsettings.Settings
import com.thewizrd.wearsettings.root.RootHelper
import com.thewizrd.wearsettings.shizuku.ShizukuUtils
import com.topjohnwu.superuser.Shell
import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper

Expand All @@ -26,7 +26,7 @@ object WifiAction {
return if (status != ActionStatus.SUCCESS) {
// Note: could have failed due to Airplane mode restriction
// Try with root
if (Shizuku.pingBinder()) {
if (ShizukuUtils.isRunning(context)) {
setWifiEnabledShizuku(context, action.isEnabled)
} else if (Settings.isRootAccessEnabled() && RootHelper.isRootEnabled()) {
setWifiEnabledRoot(action.isEnabled)
Expand Down
Loading