Galaxy Watch apps can provide a variety of options and companies, however the watch’s smaller measurement in comparison with a cellular gadget means there are limitations, together with fewer {hardware} sources and a smaller display.

To benefit from the capabilities of a cellular gadget, you’ll be able to develop a companion cellular utility for the wearable utility. The companion utility handles complicated and resource-intensive duties whereas the wearable utility gives a seamless expertise.

Previously in this series, we confirmed how one can create a companion cellular utility for a Galaxy Watch operating Put on OS powered by Samsung and use the Wearable Data Layer API to ship messages from the watch to the cellular gadget.

Whereas it’s straightforward to test the watch’s battery stage from the cellular gadget, the reverse is extra complicated. This tutorial describes how one can set up two-way communication between the wearable and cellular purposes and use it to test the cellular gadget’s battery stage from the watch.

Stipulations

To develop a wearable utility and its companion cellular utility, create a multi-module venture in Android Studio. The steps are described in the previous tutorial, and the identical dependencies and modifications are required for the wearable utility on this tutorial:

  1. Add the next dependencies to the construct.gradle file
    dependencies {
        ...
        implementation "com.google.android.gms:play-services-wearable:xx.x.x"
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x.x"
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:x.x.x"
        implementation "androidx.lifecycle:lifecycle-extensions:x.x.x"
        implementation "androidx.lifecycle:lifecycle-runtime-ktx:x.x.x"
        implementation "androidx.appcompat:appcompat:x.x.x"
    }
    
  2. Modify the MainActivity class to inherit AppCompatActivity() as an alternative of Exercise().
  3. Within the “AndroidManifest.xml” file, within the <utility> aspect, change the android:theme attribute worth to “@type/Theme.AppCompat.NoActionBar” or one other customized theme.

WarningThe bundle IDs of the wearable and cellular purposes have to be equivalent.

To check the venture, you want a Galaxy Watch operating Put on OS powered by Samsung and a related Galaxy cellular gadget.

Request battery info from the companion utility

To have the ability to retrieve the cellular gadget’s battery stage as a proportion from the watch, the companion utility on the cellular gadget should promote the “battery_percentage” functionality.

Within the cellular utility, create an XML file named “put on.xml” within the “res/values/” listing with the next content material:

<!--XML configuration file-->
<?xml model="1.0" encoding="utf-8"?>
<sources xmlns:instruments="http://schemas.android.com/instruments"
  instruments:preserve="@array/android_wear_capabilities">
  <string-array identify="android_wear_capabilities">
    <merchandise>battery_percentage</merchandise>
  </string-array>
</sources>

Whereas a watch may be related to just one gadget at a time, a cellular gadget may be related to a number of wearables on the similar time. To find out which node (related gadget) corresponds to the watch, use the CapabilityClient class of the Wearable Data Layer API to retrieve all of the obtainable nodes and choose the most effective or closest node to ship your message.

// MainActivity class within the wearable utility
non-public var batteryNodeId: String? = null
non-public enjoyable setupBatteryPercentage() {
    // Retailer the reachable nodes
    val capabilityInfo: CapabilityInfo = Duties.await( 
        Wearable.getCapabilityClient(applicationContext)
            // Retrieve all related nodes with the 'battery_percentage' functionality
            .getCapability( 
                BATTERY_PERCENTAGE_CAPABILITY_NAME,
                CapabilityClient.FILTER_REACHABLE
            )
    )

    // Use a listener to retrieve the reachable nodes
    updateBatteryCapability(capabilityInfo).additionally { capabilityListener ->
        Wearable.getCapabilityClient(this @MainActivity).addListener( 
            capabilityListener,
            BATTERY_PERCENTAGE_CAPABILITY_NAME
        )
    }
}

non-public enjoyable pickBestNodeId(nodes: Set<Node>): String? {
    // Discover the most effective node
    return nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
}

non-public enjoyable updateBatteryCapability(capabilityInfo: CapabilityInfo) {
    // Specify the recipient node for the message
    batteryNodeId = pickBestNodeId(capabilityInfo.nodes)
}

companion object{
    non-public const val TAG = "MainWearActivity"
    non-public const val BATTERY_PERCENTAGE_CAPABILITY_NAME = "battery_percentage"
    non-public const val BATTERY_MESSAGE_PATH = "/message_battery"
}

To implement bi-directional communication between watch and cellular gadget, you should use the MessageClient class of the Wearable Knowledge Layer API.

Within the wearable utility UI, create a button and a textView.

To show the cellular gadget’s battery stage on the textView when the button is tapped, implement the button’s onClickListener() operate. Ship the battery stage request message by a particular message path to the cellular gadget, utilizing a coroutine that calls the setupBatteryPercentage() and requestBatteryPercentage() strategies on a separate thread. A separate thread have to be used as a result of these are synchronous calls that block the UI thread.

// MainActivity class within the wearable utility
non-public lateinit var binding: ActivityMainBinding

override enjoyable onCreate(savedInstanceState: Bundle?) {
    tremendous.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    Log.d(TAG, "onCreate()")

    binding.apply{
        phoneButton.setOnClickListener{
            lifecycleScope.launch(Dispatchers.IO){
                setupBatteryPercentage()
                requestBatteryPercentage("Battery".toByteArray())
            }
        }
    }
}
// Ship the message to the chosen node
non-public enjoyable requestBatteryPercentage(information: ByteArray) {
    batteryNodeId?.additionally { nodeId ->
        val sendTask: Activity<*> = Wearable.getMessageClient(this @MainActivity).sendMessage(
            nodeId,
            BATTERY_MESSAGE_PATH,
            information
        ).apply {
            addOnSuccessListener { Log.d(TAG, "OnSuccess") }
            addOnFailureListener { Log.d(TAG, "OnFailure") }
        }
    }
 }

Obtain the message on the companion utility

The companion utility should have the ability to obtain and reply to the message from the background. To perform this, implement a service that listens for incoming messages.

Within the cellular utility, create a category that extends WearableListenerService() and add the service to the appliance manifest file:

<!--Android manifest file for the cellular application-->
<service
    android:identify=".PhoneListenerService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <motion android:identify="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
        <information
            android:host="*"
            android:pathPrefix="https://developer.samsung.com/"
            android:scheme="put on" />
    </intent-filter>
</service>

Use the batteryManager class to retrieve the present battery stage of the gadget. To ship the retrieved worth again to the wearable utility, use the sendMessage() operate once more. For simplicity, ship the message to the primary related node on the cellular gadget. Alternatively, you’ll be able to broadcast to all related nodes.

Implement the OnMessageReceived() operate to obtain the incoming request for battery stage and ship the retrieved worth to the wearable utility.

// Service class within the cellular utility
non-public val scope = CoroutineScope(SupervisorJob() + Dispatchers.Most important.speedy)
non-public var batteryNodeId: String? = null

override enjoyable onDestroy() {
    scope.cancel()
    tremendous.onDestroy()
}

override enjoyable onMessageReceived(messageEvent: MessageEvent) {
    Log.d(TAG, "onMessageReceived(): $messageEvent")
    Log.d(TAG, String(messageEvent.information))
    if (messageEvent.path == BATTERY_MESSAGE_PATH && String(messageEvent.information) == "Battery") { 
        // Examine that the request and path are appropriate
        val batteryManager = applicationContext.getSystemService(BATTERY_SERVICE) as BatteryManager

        val batteryValue:Int = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        scope.launch(Dispatchers.IO){
            // Ship the message to the primary node
            batteryNodeId = getNodes().first()?.additionally { nodeId-> 
                val sendTask: Activity<*> = Wearable.getMessageClient(applicationContext).sendMessage(
                    nodeId,
                    BATTERY_MESSAGE_PATH,
                    batteryValue.toString().toByteArray()
                ).apply {
                    addOnSuccessListener { Log.d(TAG, "OnSuccess") }
                    addOnFailureListener { Log.d(TAG, "OnFailure") }
                }
            }
        }
    }
    onDestroy()
}

non-public enjoyable getNodes(): Assortment<String> {
    return Duties.await(Wearable.getNodeClient(this).connectedNodes).map { it.id }
}

companion object{
    non-public const val TAG = "PhoneListenerService"
    non-public const val BATTERY_MESSAGE_PATH = "/message_battery"
}

Show the battery info on the wearable utility

When receiving the battery info on the wearable utility, as a result of the person is actively interacting with the appliance, a resource-intensive service just isn’t wanted and registering a dwell listener is adequate. Use the addListener() technique of the MessageClient class to implement the MessageClient.OnMessageReceivedListener interface inside the MainActivity class within the wearable utility.

// MainActivity class within the wearable utility
override enjoyable onResume(){
    tremendous.onResume()
    Log.d(TAG, "onResume()")
    // Wearable API purchasers aren't resource-intensive
    Wearable.getMessageClient(this).addListener(this) 
}

override enjoyable onPause(){
    tremendous.onPause()
    Log.d(TAG, "onPause()")
    Wearable.getMessageClient(this).removeListener(this)
}

override enjoyable onMessageReceived(messageEvent: MessageEvent) {
    // Obtain the message and show it
    if(messageEvent.path == BATTERY_MESSAGE_PATH){
        Log.d(TAG, "Cellular battery proportion: " + String(messageEvent.information) + "%")
        binding.phoneTextView.textual content = String(messageEvent.information)
    }
}

Conclusion

To check the venture, construct each purposes and run them in your Galaxy Watch and cellular gadget. Once you faucet the UI button on the watch, the appliance retrieves the battery stage from the cellular gadget and shows the proportion on the watch.

This demonstration has proven how the Wearable Knowledge Layer API allows you to implement seamless bi-directional communication between a Galaxy Watch operating Put on OS powered by Samsung and its related cellular gadget. Along with battery stage, you should use the CapabilityClient and MessageClient lessons to switch varied information between the gadgets in the same means.

For extra details about implementing communication between watch and cellular gadgets, see Send and receive messages on Wear.

If in case you have questions on or need assistance with the data on this tutorial, you’ll be able to share your queries on the Samsung Developers Forum. For extra specialised assist, you’ll be able to contact us by Samsung Developer Support.

Keep tuned for the subsequent installment on this tutorial collection.