Download library here: https://www.b4x.com/android/forum/threads/abwearos-library-1-0.98036/
This library requires B4A 8.50+
This library should implement the new datalayer Google Api to send and sync data on Wear and uses the latest Google Play services (SDK 28)
I tried to convert the older API @barx wrote, however there were a lot of changes so in the end, the two libraries are not compatible. In many ways, the new API is actually a lot simpler.
I have not been able to test everything of this library. A lot is tested because I used in in an app I wrote, but the e.g. Channel Api has not. Report back (with example code if possible) if problems should come up.
The library doc:
ABWearOS
Author: Alain Bailleul
Version: 1
Installation:
Copy all four jar files to your Additional libraries folder. In the library manager, select ABWearOS.
-- Mobile --
Additional jars in Region Project Attributes:
Manifest:
-- Wear --
Additional jars in Region Project Attributes:
If you want the app to always stay in front, you will need to activate the ambient mode.
In #Region Activity Attributes add:
Manifest:
The ABWearOS library can be defined ONLY once in your project and you must share the same instance in other activities/services. All the events will be raised in the activity/service where ABWearOS is defined.
e.g. if you have have in your main activity, then all events wll be raised in THIS activity:
In the Activity_Create (or Service_Create) initialize them:
In Activity_Resume (or Service_Start) you do the connect:
In Activity_Pause (or Service_Destroy) you disconnect:
Inbetween you can do all kind of stuff. In most cases you will want to run wear.GetConnectedNodes first so you get a list of all the devices connected. Google Play Services acts a bit like MQTT, so you send messages (or datamaps) between devices using a path (e.g. "/mypath" and a nodeid. This node id you get by running GetConnectedNodes() and GetLocalNode() to get your own nodeId.
All calls to the library run in seperate threads: this means a call you do will never immidiately return a result, you will have to wait for an event. e.g. wear.SendMessage() will return the wear_MessageSent event. Check out the help to see which event is returned by which function.
Some calls will return two events, e.g. the ChannelClose method will return two events. One on the sending device and one on the receiving device:
if this called succeeds on the calling device:
will be raised on the remote device:
This library requires B4A 8.50+
This library should implement the new datalayer Google Api to send and sync data on Wear and uses the latest Google Play services (SDK 28)
I tried to convert the older API @barx wrote, however there were a lot of changes so in the end, the two libraries are not compatible. In many ways, the new API is actually a lot simpler.
I have not been able to test everything of this library. A lot is tested because I used in in an app I wrote, but the e.g. Channel Api has not. Report back (with example code if possible) if problems should come up.
The library doc:
ABWearOS
Author: Alain Bailleul
Version: 1
- ABWearOSDataMap
Methods:- Size As int
Returns the number of Key-Value pairs currently in the DataMap - PutByte (Key As java.lang.String, Val As byte) As void
Adds a Byte data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - Remove (Key As java.lang.String) As void
Removes an item from the DataMap with the given Key - IsInitialized As boolean
- Initialize (ba As anywheresoftware.b4a.BA) As void
Initializes the object.
No Eventname is required. The DataLayer Eventname is used. - GetFloat (Key As java.lang.String) As float
Gets a Float data item from the DataMap
Key - The reference as set in in the PutFloat() method - Clear As void
Clears all previously added data items from the DataMap - PutAsset (Key As java.lang.String, Asset As com.google.android.gms.wearable.Asset) As void
Adds an Asset data item to the DataMap
Key - a key used to reference the data item
Asset - the Asset object to pass. - GetLongArray (Key As java.lang.String) As long[]
Gets a Long Array data item from the DataMap
Key - The reference as set in in the PutLongArray() method - GetByteArray (Key As java.lang.String) As byte[]
Gets a Byte Array data item from the DataMap
Key - The reference as set in in the PutByteArray() method - PutByteArray (Key As java.lang.String, Val As byte[]) As void
Adds a Byte Array data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - PutDouble (Key As java.lang.String, Val As double) As void
Adds a Double data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - GetStringArray (Key As java.lang.String) As java.lang.String[]
Gets a StringArray data item from the DataMap
Key - The reference as set in in the PutStringArray method - GetAsset (Key As java.lang.String) As com.google.android.gms.wearable.Asset
Gets an Asset data item from the DataMap
Key - The reference as set in in the PutAsset() method - GetDouble (Key As java.lang.String) As double
Gets a Double data item from the DataMap
Key - The reference as set in in the PutDouble() method - GetBoolean (Key As java.lang.String) As java.lang.Boolean
Gets a Boolean data item from the DataMap
Key - The reference as set in in the PutBoolean() method - GetByte (Key As java.lang.String) As byte
Gets a Byte data item from the DataMap
Key - The reference as set in in the PutByte() method - GetLong (Key As java.lang.String) As long
Gets a Long data item from the DataMap
Key - The reference as set in in the PutLong() method - isEmpty As boolean
Return True if the DataMap is currently empty - PutInt (Key As java.lang.String, Val As int) As void
Adds an Int data item to the DataMap.
Key - a key use to reference the data item
Val - the value to set to. - PutLong (Key As java.lang.String, Val As long) As void
Adds a Long data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - ContainsKey (Key As java.lang.String) As boolean
Checks if the given key is contained in the DataMap.
Returns True if the key is present - GetFloatArray (Key As java.lang.String) As float[]
Gets a Float Array data item from the DataMap
Key - The reference as set in in the PutFloatArray() method - PutBoolean (Key As java.lang.String, Val As java.lang.Boolean) As void
Adds a Boolean data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - PutLongArray (Key As java.lang.String, Val As long[]) As void
Adds a Long Array data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - GetInt (Key As java.lang.String) As int
Gets an Int data item from the DataMap
Key - The reference as set in in the PutInt() method - PutStringArray (Key As java.lang.String, Val As java.lang.String[]) As void
Adds a String Array data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - Get (Key As java.lang.String) As java.lang.Object
Returns the DataMap entry with the given Key as an Object - toByteArray As byte[]
Returns the DataMap as a ByteArray - GetString (Key As java.lang.String) As java.lang.String
Gets a String data item from the DataMap
Key - The reference as set in in the PutString() method - PutString (Key As java.lang.String, Val As java.lang.String) As void
Adds a String data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - toString As java.lang.String
Returns a string representation of the DataMap - PutFloat (Key As java.lang.String, Val As float) As void
Adds a Float data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to. - PutFloatArray (Key As java.lang.String, Val As float[]) As void
Adds a Float Array data item to the DataMap
Key - a key used to reference the data item
Val - the value to set to.
- Size As int
- ABWearOSChannel
Methods:- GetInputStream As void
Get an input stream which can read data from the remote node.
event: ChannelInputStreamResult(Success as Boolean, NodeId as String, Stream As InputStream) - GetOutputStream As void
Get an output stream which can send data to a remote node.
event: ChannelOutputStreamResult(Success as Boolean, NodeId as String, Stream As OutputStream)
- Path As java.lang.String [read only]
Returns the path that was used to open the channel. - NodeId As java.lang.String [read only]
Returns the node ID of the node on the other side of the channel. - DescribeContents As int [read only]
Returns one of the CHANNEL_ constants
- GetInputStream As void
- ABWearOSAmbient
Events:- Enter (IsLowBitAmbient As Boolean, DoBurnInProtection As Boolean)
- Update (IsAmbient as Boolean As )
- Exit ( As )
- Initialize (ba As anywheresoftware.b4a.BA, EventName As java.lang.String) As void
Initializes the object and sets the subs that will handle the events.
- ABWearOS
Events:- LocalNodeIDResult (Success As boolean, NodeId as String As , NodeDisplayName As String)
- NodeResults (Success As Boolean, Results As List)
- MessageSent (Success As Boolean, Path as String As , Node as String As )
- MessageReceived (SourceNodeID As String, RequestID As Int, msgPath As String, Data As String)
- DataMapDeleted (Success As Boolean, Path as string As )
- DataMapResults (Success As Boolean, Results As Map)
- DataMapResult (Success As Boolean, Tag As String, Result As DataMap)
- DataMapAdded (Success As Boolean, Path As String)
- DataChanged (ChangedItems As Map, DeletedItems As Map)
- BitmapResult (Success As Boolean, Tag As String, Result As Bitmap)
- FileResult (Success as Boolean As , Tag As String, Dir As String, Filename As String)
- CapabilityChanged (Name as String As , Nodes as List As )
- CapabilityAdded (Success as Boolean As , Capability As String)
- CapabilityRemoved (Success as Boolean As , Capability As String)
- CapabilitiesResults (Success As Boolean, Results as List As )
- CapabilityResult (Success As Boolean, Capability as String As , Results as List As )
- ChannelInputStreamResult (Success as Boolean As , NodeId as String As , Stream As InputStream)
- ChannelOutputStreamResult (Success as Boolean As , NodeId as String As , Stream As OutputStream)
- ChannelCloseResult (Success as Boolean As , Channel as ABWearOSChannel As )
- ChannelOpenResult (Success as Boolean As , channel As ABWearOSChannel)
- ChannelClosed (Channel as ABWearOSChannel As , closeReason as int As , errorCode as int As )
- ChannelOpened (Channel as ABWearOSChannel As )
- ChannelInputClosed (Channel as ABWearOSChannel As , closeReason as int As , errorCode as int As )
- ChannelOutputClosed (Channel as ABWearOSChannel As , closeReason as int As , errorCode as int As )
- ChannelReceiveFileResult (Success as Boolean As )
- ChannelSendFileResult (Success as Boolean As )
- CLOSE_REASON_DISCONNECTED As int
- CAPABILITY_FILTER_REACHABLE As int
- CHANNEL_CLOSE_REASON_DISCONNECTED As int
- CHANNEL_CLOSE_REASON_LOCAL_CLOSE As int
- CLOSE_REASON_LOCAL_CLOSE As int
- CAPABILITY_FILTER_LITERAL As int
- CAPABILITY_FILTER_PREFIX As int
- CLOSE_REASON_NORMAL As int
- CAPABILITY_FILTER_ALL As int
- CHANNEL_CLOSE_REASON_REMOTE_CLOSE As int
- CLOSE_REASON_REMOTE_CLOSE As int
- CHANNEL_CONTENTS_FILE_DESCRIPTOR As int
- CHANNEL_PARCELABLE_WRITE_RETURN_VALUE As int
- CHANNEL_CLOSE_REASON_NORMAL As int
- RemoveLocalCapability (capability As java.lang.String) As void
Announces that a capability is no longer available on the local node.
Note: this will not remove any capabilities announced in the Manifest for an app.
event: CapabilityRemoved (Success as boolean, Capability as String) - GetConnectedNodes As void
Get a list of the connected Nodes (Devices)
event: NodeResults(Success, List)
The returned List will contains a Map for each node (Case Sensitive!).
The map will then contain 3 Key-Value pairs:
ID - The ID of the node, this is used to reference the node when sending messages etc
DisplayName - A HumanReadable name for the device (on my Samsung Gear Live this matched the ID so was of no use)
IsNearby - boolean is the device is nearby - GetCapability (capability As java.lang.String, nodeFilter As int) As void
Returns information about a capability, including the nodes that declare that capability.
The nodeFilter parameter controls whether all nodes are returned, CAPABILITY_FILTER_ALL,
or only those that are currently reachable by this node, CAPABILITY_FILTER_REACHABLE.
event: CapabilityResult(Success As Boolean, Capability as String, Results as List)
The returned List will contains a Map for each node (Case Sensitive!).
The map will then contain 3 Key-Value pairs:
ID - The ID of the node, this is used to reference the node when sending messages etc
DisplayName - A HumanReadable name for the device (on my Samsung Gear Live this matched the ID so was of no use)
IsNearby - boolean is the device is nearby - AddDataMap (path As java.lang.String, datamap As com.google.android.gms.wearable.DataMap) As void
Adds a Data Map to the Client to sync across the Wearable Data connection.
DataMaps are synchronized across all devices
Path - The path to store the DataMap under. e.g "/User"
DataMap - The DataMap object to add
event: DataMapAdded(Success, path) - AssetToFile (tag As java.lang.String, asset As com.google.android.gms.wearable.Asset, targetDir As java.lang.String, targetFileName As java.lang.String) As void
Convert an Asset to a File
Tag - A tag used to identify the request in the resulting callback
Asset - The Asset object to extract the File from.
TargetDir - The directory where the File will be created
TargetFilename - The filename that the extracted File will be named
event: FileResult(success, tag, targetdir, targetFileName) - Initialize (ba As anywheresoftware.b4a.BA, Eventname As java.lang.String) As void
Initializes the object. - Disconnect As void
Disconnects the Google Play services client
Should always be called once you have finished with the Data Layer e.g. when the app closes or is paused. - GetAllDataMaps As void
Get all the present DataMaps as a Map.
Each Map Key-Value pair is as follows
Key - The path that the DataMap resides
Value - The DataMap object
Event: DataMapResults(Success, Results) - GetLocalNode As void
Returns the local node id
event: LocalNodeIDResult(success, nodeId, nodeDisplayName) - GetDataMap (path As java.lang.String, tag As java.lang.String) As void
Get a DataMap.
Event: DataMapResult(Success, Tag , Result) - ReceiveFile (channel As com.ab.abwearos.ABWearOSChannel, filePath As java.lang.String, fileName As java.lang.String, append As boolean) As void
Reads input from a channel into a file. This is equivalent to calling GetInputStream(), reading from the input stream and writing it to a file,
but is implemented more efficiently. Writing to the file will be done in a background process owned by Google Play services.
This method should only be used once on any channel, and once it has been called, GetInputStream() cannot be used.
The channel should not be immediately closed after calling this method.
events: ChannelReceiveFileResult(Success as boolean) if the call succeeded
ChannelInputClosed(Channel as ABWearOSChannel, closeReason as int, errorCode as int) when the file is received - BitmapToAsset (bitmap As android.graphics.Bitmap) As com.google.android.gms.wearable.Asset
Convert a Bitmap to an Asset - SendMessage (path As java.lang.String, node As java.lang.String, message As java.lang.String) As void
Sends a message to a specified node
event: MessageSent(Success, path, node) - GetAllCapabilities (nodeFilter As int) As void
Returns information about all capabilities, including the nodes that declare those capabilities.
The nodeFilter parameter controls whether all nodes are returned, CAPABILITY_FILTER_ALL,
or only those that are currently reachable by this node, CAPABILITY_FILTER_REACHABLE.
event: CapabilitiesResults(Success as Boolean, Results as List)
Is a lists of Maps. The map will then contain 2 Key-Value pairs:
Name - Capability name
Nodes - A list of Maps: the map will then contain 3 Key-Value pairs:
ID - The ID of the node, this is used to reference the node when sending messages etc
DisplayName - A HumanReadable name for the device (on my Samsung Gear Live this matched the ID so was of no use)
IsNearby - boolean is the device is nearby - AddLocalCapability (capability As java.lang.String) As void
Announces that a capability has become available on the local node.
event: CapabilityAdded (Success as boolean, Capability as String) - AssetToBitmap (tag As java.lang.String, asset As com.google.android.gms.wearable.Asset) As void
Convert an Asset to a Bitmap
Tag - a Tag used to identify the request in the resulting callback
Asset - the Asset object to extract the File from
event: BitmapResult(success, tag, bitmap) - FileToAsset (Dir As java.lang.String, Filename As java.lang.String) As com.google.android.gms.wearable.Asset
Convert a File to an Asset - Connect As void
Connects the Google Play services client (required for the Data Layer to work)
Make sure you disconnect the client once done (probably best to do this in Activity_Pause() - DeleteDataMap (path As java.lang.String) As void
Deletes a DataMap
event: DataMapDeleted(Success, path) - SendFile (channel As com.ab.abwearos.ABWearOSChannel, filePath As java.lang.String, fileName As java.lang.String) As void
Reads from a file into the output side of a channel. This is equivalent to calling GetOutputStream(),
reading from a file and writing into the OutputStream, but is implemented more efficiently.
Reading from the file will be done in a background process owned by Google Play services.
This method should only be used once on any channel, and once it has been called, GetOutputStream() cannot be used.
The channel should not be immediately closed after calling this method.
events: ChannelSendFileResult(Success as boolean) if the call succeeded
ChannelOutputClosed(Channel as ABWearOSChannel, closeReason as int, errorCode as int) when the file is send - SendFileOffset (channel As com.ab.abwearos.ABWearOSChannel, filePath As java.lang.String, fileName As java.lang.String, offset As long, length As long) As void
Reads from a file into the output side of a channel. This is equivalent to calling GetOutputStream(),
reading from a file and writing into the OutputStream, but is implemented more efficiently.
Reading from the file will be done in a background process owned by Google Play services.
This method should only be used once on any channel, and once it has been called, GetOutputStream() cannot be used.
The channel should not be immediately closed after calling this method.
events: ChannelSendFileResult(Success as boolean) if the call succeeded
ChannelOutputClosed(Channel as ABWearOSChannel, closeReason as int, errorCode as int) when the file is send - ChannelClose (channel As com.ab.abwearos.ABWearOSChannel, errorCode As int) As void
Closes a channel, passing an application-defined error code to the remote node.
The error code will be passed to ChannelClosed event, and will cause remote reads and writes to the channel to fail.
The InputStream and OutputStream returned from GetInputStream() or GetOutputStream(l) should be closed prior to calling this method.
If they are not, both streams will throw an exception.
errorCode = 0 is used to indicate that no error occurred.
events: ChannelCloseResult(Success As Boolean, Channel as ABWearOSChannel) if this called succeeds on the calling device
ChannelClosed(Channel as ABWearOSChannel, closeReason as int, errorCode as int) will be raised on the remote device - ChannelOpen (nodeId As java.lang.String, path As java.lang.String) As void
Opens a channel to exchange data with a remote node.
Channel which are no longer needed should be closed using close(Channel).
This call involves a network round trip, so may be long running.
Client must remain connected during that time, or the request will be cancelled (like any other Play Services API calls).
events: ChannelOpenResult(Success As Boolean, Channel As ABWearOSChannel) if this called succeeds on the calling device
ChannelOpened(Channel as ABWearOSChannel) will be raised on the remote device
- ShowDebug As boolean [write only]
Shows some debug info from within the library
Installation:
Copy all four jar files to your Additional libraries folder. In the library manager, select ABWearOS.
-- Mobile --
Additional jars in Region Project Attributes:
B4X:
#AdditionalJar: com.google.android.gms:play-services-wearable
#AdditionalJar: com.android.support:wear
Manifest:
B4X:
AddManifestText(
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
<supports-screens android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
CreateResourceFromFile(Macro, Themes.DarkTheme)
'End of default text.
AddPermission(android.permission.READ_EXTERNAL_STORAGE)
AddPermission(android.permission.WRITE_EXTERNAL_STORAGE)
AddApplicationText(<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
)
-- Wear --
Additional jars in Region Project Attributes:
B4X:
#AdditionalJar: com.google.android.gms:play-services-wearable
#AdditionalJar: com.android.support:wear
If you want the app to always stay in front, you will need to activate the ambient mode.
In #Region Activity Attributes add:
B4X:
#Extends: com.ab.abwearos.ABWearOSAmbient
Manifest:
B4X:
AddManifestText(
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="26"/>
<uses-feature android:name="android.hardware.type.watch"/>
)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
CreateResourceFromFile(Macro, Themes.DarkTheme)
'End of default text.
AddPermission(android.permission.READ_EXTERNAL_STORAGE)
AddPermission(android.permission.WAKE_LOCK)
AddApplicationText(<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<uses-library android:name="com.google.android.wearable" android:required="false" />
)
The ABWearOS library can be defined ONLY once in your project and you must share the same instance in other activities/services. All the events will be raised in the activity/service where ABWearOS is defined.
e.g. if you have have in your main activity, then all events wll be raised in THIS activity:
B4X:
Sub Globals
' can be accessed from all modules
public wear As ABWearOS
End Sub
The ambient mode is to keep your app in the forgroud, if you app goes in ambient mode. Can be handy e.g. for a walking app.
Sub Globals
' is an activity object, so must be declared here.
Private ambient As ABWearOSAmbient
End Sub
In the Activity_Create (or Service_Create) initialize them:
B4X:
ambient.Initialize("ambient")
wear.Initialize("wear")
In Activity_Resume (or Service_Start) you do the connect:
B4X:
wear.connect
In Activity_Pause (or Service_Destroy) you disconnect:
B4X:
wear.disconnect
Inbetween you can do all kind of stuff. In most cases you will want to run wear.GetConnectedNodes first so you get a list of all the devices connected. Google Play Services acts a bit like MQTT, so you send messages (or datamaps) between devices using a path (e.g. "/mypath" and a nodeid. This node id you get by running GetConnectedNodes() and GetLocalNode() to get your own nodeId.
All calls to the library run in seperate threads: this means a call you do will never immidiately return a result, you will have to wait for an event. e.g. wear.SendMessage() will return the wear_MessageSent event. Check out the help to see which event is returned by which function.
Some calls will return two events, e.g. the ChannelClose method will return two events. One on the sending device and one on the receiving device:
if this called succeeds on the calling device:
B4X:
ChannelCloseResult(Success As Boolean, Channel as ABWearOSChannel)
will be raised on the remote device:
B4X:
ChannelClosed(Channel as ABWearOSChannel, closeReason as int, errorCode as int)
Last edited: