Android Tutorial ABWearOS Library 1.0

alwaysbusy

Expert
Licensed User
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
  • 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.
  • 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)
    Properties:
    • 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
  • ABWearOSAmbient
    Events:
    • Enter (IsLowBitAmbient As Boolean, DoBurnInProtection As Boolean)
    • Update (IsAmbient as Boolean As )
    • Exit ( As )
    Methods:
    • 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 )
    Fields:
    • 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
    Methods:
    • 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
    Properties:
    • 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:

alwaysbusy

Expert
Licensed User
A snippet from the app I wrote which shows how to send a datamap from the mobile phone to the wear app:

' mobile, wear is defined in a service and it has a method StartGame() where I upload my golf clubs to the wear app:
B4X:
public Sub StartGame()
   ' Mapclubs is dimmed in Process_Globals as: Private MapClubs As ABWearOSDataMap
   MapClubs.Initialize

   wear.Connect
   wear.GetConnectedNodes
   
   Dim clubs As List = GetClubs
   MapClubs.Clear
   MapClubs.PutString("MapType", "MapClubs")
   Dim Keys As List
   Keys.Initialize
   For i = 0 To clubs.Size - 1
       Dim club As clsClub = clubs.Get(i)
       MapClubs.PutString(club.ClubName, club.ToString)
       Keys.Add(club.ClubName)
   Next
   MapClubs.PutStringArray("Keys", ToArray(Keys))
   wear.AddDataMap("/golfcaddy", MapClubs)
End Sub

Sub ToArray(l As List) As String()
   Dim ArrayOf(l.Size) As String
   For i = 0 To l.Size - 1
       ArrayOf(i) = l.Get(i)
   Next
   Return ArrayOf
End Sub
' wear device (wear is defined in the activity here):
B4X:
Sub wear_DataChanged(ChangedItems As Map, DeletedItems As Map)
   For Each key As String In ChangedItems.Keys
       Dim m As ABWearOSDataMap = ChangedItems.get(key)
       Dim MapType As String = m.GetString("MapType")
       Select Case MapType
           Case "MapClubs"
               Log("New clubs")
               
               RealClubs.Clear
               Dim keys() As String = m.GetStringArray("Keys")
               For i = 0 To keys.Length - 1
                   Dim club As clsClub
                   club.Initialize
                   club.FromString(m.GetString(keys(i)))
                   RealClubs.Add(club)
               Next
          Case ' it does other things like handeling an uploaded course
              ...
      End Select
   Next
End Sub
 

fabpalma

Member
Licensed User
Hi, first many thanks for your job !!
I am trying to compile your example but I got immediatly an error:

B4A Version: 7.80
Code analysis. (0.00s)
Code compilation. error
Reference to an object not set on an object instance.

(translated from italian)

But in the code editor I'm not able to see any error.
Can I use B4A version 7.80 or I need to upgrade ?
I have solved all the maven* missing alerts but it wasn't enough !

Do I need to copy some jar file from SDK into library folder ?

Thanks in advance.
Regards
 

alwaysbusy

Expert
Licensed User
I'm using B4A 8.50. It is possible that only the later version of B4A can use these type of #AdditionJars, but I'm not sure. The jars included in the zip should be enough (if you have installed the complete SDK 28 and pointed B4A to android-28\android.jar).

Maybe wait until @Erel gives an answer if 7.80 is enough for Android SDK 28.

Is there someone who uses B4A 8.50 and has the same problem? If so, then I will have to investigate.
 

Peter Simpson

Expert
Licensed User
I'm using B4A 8.50. It is possible that only the later version of B4A can use these type of #AdditionJars, but I'm not sure. The jars included in the zip should be enough (if you have installed the complete SDK 28 and pointed B4A to android-28\android.jar).

Maybe wait until @Erel gives an answer if 7.80 is enough for Android SDK 28.

Is there someone who uses B4A 8.50 and has the same problem? If so, then I will have to investigate.
Nope, withing minutes of you adding your example, I had got it working with B4A v8.50, Java 10.0.2, SmartWatch is Android OS 8.0.0 with Wear OS 2.0.

Thank you...
 
Last edited:

fabpalma

Member
Licensed User
I purchased the update to version 8.50 and I recompiled the project without changing anything and it was successful.
Evidently there are some features required in version 8.50.
I think it's better to write it in the library post.

Now I can try the alwaysbusy library!
Thank you.
 

seskindell

Active Member
Licensed User
I have 8.5 installed. I am getting the error message "Maven artifact not found: com.android.support/wear". I am setup with jdk-10.0.2 and Android-28 (everything installed).

Please help.
 
Last edited:

fabpalma

Member
Licensed User
Run SDK Manager from B4A IDE and check that com.android.support:wear (Google Maven) Version 28.0.0 is installed.
Otherwise, select it and press [Install Selected].
You have to do the same for every missing reference.
 

seskindell

Active Member
Licensed User
Tried to compile the sample template for the mobile and wear devices. Using 8.5 with everything installed correctly.
The mobile app compiles fine. The Wear device (which is a gen 4 fossil smart watch) brings up the following errors:

Logger connected to: samsung SM-G900V
--------- beginning of main
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
*** Service (wearservice) Create ***
** Service (wearservice) Start **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
** Service (wearservice) Start **
Partial wakeLock already held.
** Activity (main) Pause, UserClosed = false **
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
main_activity_create (java line: 357)
java.lang.ClassCastException: com.ab.weardemo.main cannot be cast to com.ab.abwearos.ABWearOSAmbient
at com.ab.abwearos.ABWearOSAmbient$ABWearOSAmbientListener.Initialize(ABWearOSAmbient.java:112)
at com.ab.weardemo.main._activity_create(main.java:357)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:191)
at com.ab.weardemo.main.afterFirstLayout(main.java:104)
at com.ab.weardemo.main.access$000(main.java:17)
at com.ab.weardemo.main$WaitForLayout.run(main.java:82)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5835)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
GetConnectedNodes: 1 found
true
7f1514ae: Q Explorist HR 2784
** Activity (main) Pause, UserClosed = false **
 

seskindell

Active Member
Licensed User
These are the errors I get when I try compiling the wear app from the template (no changes to the template code) -- using SDK 28:

PackageAdded: package:com.ab.weardemo
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ab.weardemo/com.ab.weardemo.main}: java.lang.IllegalStateException: Could not find wearable shared library classes. Please add <uses-library android:name="com.google.android.wearable" android:required="false" /> to the application manifest
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2661)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.access$900(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5835)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.IllegalStateException: Could not find wearable shared library classes. Please add <uses-library android:name="com.google.android.wearable" android:required="false" /> to the application manifest
at android.support.wear.ambient.SharedLibraryVersion.verifySharedLibraryPresent(SharedLibraryVersion.java:57)
at android.support.wear.ambient.WearableControllerProvider.getWearableController(WearableControllerProvider.java:48)
at android.support.wear.ambient.AmbientDelegate.onCreate(AmbientDelegate.java:103)
at android.support.wear.ambient.AmbientModeSupport.onCreate(AmbientModeSupport.java:198)
at android.support.v4.app.Fragment.performCreate(Fragment.java:2414)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1418)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
at com.ab.weardemo.main.onStart(main.java:175)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1234)
at android.app.Activity.performStart(Activity.java:6258)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624)
... 10 more
 

alwaysbusy

Expert
Licensed User
Logger connected to: samsung SM-G900V
Are you trying to run the wear app on your phone? it will only run on a wear device connected to your pc and it should be running Wear OS 2.0+. If your watch doesn’t support ambient mode, you can try removing the #Extends line, the ABWearOSAmbient library (and relevant code)
 

seskindell

Active Member
Licensed User
I am running OS 2.0 on the watch. How do you install the app to the watch? I thought it would automatically install.
Thank you,
Steve
 

seskindell

Active Member
Licensed User
Are you trying to run the wear app on your phone? it will only run on a wear device connected to your pc and it should be running Wear OS 2.0+. If your watch doesn’t support ambient mode, you can try removing the #Extends line, the ABWearOSAmbient library (and relevant code)
Yes ... I was trying to run the Wear app of the template on the Mobile rather than the wear device.
I finally viewed tutorials on Youtube to figure out how to install the demo.apk on the watch wear device.
I had to configure debugging wifi on the watch and find the ip address of the watch. Then I issued the dos commands:

adb forward tcp:5555 localabstract:/adb-hub
adb connect 10.0.1.41:5555
(10.0.1.41 is the ip address of the watch)

Once the connection was made I issued the command from DOS:

adb -e install demo.apk

That installed the app on the watch.

It would be really helpful to have a button and edittext field on both the wear device and the mobile device and show how the
edittext string goes from the mobile device to the wear device .. and how the edittext string goes from the wear device to the mobile device when the
respective button is pressed. That would be REALLY helpful to me.

- Steve
 
Top