B4A Library Wearable DataLayer

What is it?
Not so recently a new branch of the Android platform was released for wearables (Watches and things) know simply as Android Wear. Wearables running Android Wear are made to be an extension for your existing mobile Android device. They bring notifications and app information / interaction out of your pocket and onto your wrist (and maybe other places if other wearable devices are released). I believe notifications will account for about 80% of the usage of these wearable devices. Wearable notification support has been possible for a while with the Notification Builder library, and the possibility to make apps that run on Android Wear has also been possible Tutorial. There was still a little issue; your mobile device and your wearable device couldn't talk to each other.

So, here is the Wearable DataLayer library. It allows you to communicate between the 2 devices. There are a couple of ways this works. There are:
  • Messages - these are 'send and forget' one way messages for small amounts of information (<100 KB)
  • DataMaps (Google call them DataItems, externally, but DataMaps internally o_O) - These are maps of data that are kept in sync on the Wear Network (a virtual connection between the devices). This data can be changed from either side and the data will sync to all other devices. DataMaps can hold Strings, Ints, Booleans, etc.
  • Assets - These are technically part of DataMaps but it is easier to explain them separately and you create them like so. Assets are basically used to transfer larger (anything > 100 KB) blocks of information as a File or Bitmaps. Assets are added to DataMaps and the system takes care of the transfer over bluetooth and caching, avoiding re-transmission.
This library has literally taken me an lifetime to make and I can only apologize for that, I hoped it would have been waaaaaay before now but sometimes life gets in the way of hobbies.

How To Install

First of all, copy the .jar and .xml to your additional libraries folder like any other library.

The use of this library requires the inclusion of Google Play Services. Similar to the Android-Support libraries, you have to download this with sdk manager and copy the library file(s) over to your additional libraries folder. A typical place for this would be

C:\Program Files\Android\sdk\extras\google\google_play_services\libproject\google-play-services_lib\libs

Although this path may be different depending on your installation.

It also requires 'AdditionalRes'. Again the path may vary. This is just for the Version ID of Play Services.
#AdditionalRes: C:\Program Files\Android\sdk\extras\google\google_play_services\libproject\google-play-services_lib\res, com.google.android.gms

I will update that post a little in the future and also create / post a few simple examples to help you all out.

Note: I have edited a few bits since my last BIG testing session, hopefully it won't have broken anything. I've run a few tests but thought it was about time I got this online so I will fix any issues as they come up. Also, a lot has changed since the BETA so the examples for that won't work, though the principles are the same so you should be able to get the idea from it.

Documentation

WearableDataLayer
Author:
BarxDroid
Version: 1

  • Methods:
    • AddDynamicListener
      Adds a dynamic listener to receive message events.
      A dynamic listener is create at runtime and will be removed once the process is stopped or once RemoveListener is called.
    • Info
      NOTE: This method doesn't do anything and is to provide information only.
      A Message is used to 'Send and forget' small amounts (<100KB) of data.
      You can receive the messages either with dynamic or static receivers.
      Dynamic - Will only be received while the listener is registered.
      Register with .AddDynamicReceiver.
      You must also unregister once done using .RemoveDynamicReceiver
      static - More complex but means you can receive messages at any time
      Add the following text to the Manifest Editor
      <code>AddApplicationText(
      <service android:name="barxdroid.wearabledatalayer.ListenerService"
      android:label="Wearable Listener">
      <intent-filter>
      <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
      </intent-filter>
      </service>)
      </code>
      Then add a service called 'WearListenerService to your project and in the service module, use code like this.
      <code>
      Sub Process_Globals
      Dim WL As WearableListener
      End Sub
      Sub Service_Start (StartingIntent As Intent)
      WL.Initialize("WL")
      WL.HandleIntent(StartingIntent)
      End Sub
      Sub WL_MessageReceived(SourceNodeID As String, RequestID As Int, msgPath As String, Data As String)
      ToastMessageShow(Data, False)
      End Sub
      </code>
    • IsInitialized As Boolean
    • RemoveListener
      Removes the dynamic listener so no more messages will be received
    • Send (NodeID As String, Timeout As Long, msgPath As String, Data As String)
      Sends a message to a specified node
      NodeID - The ID of the node to connect to.
      Timeout - The timeout before the message sending will fail in milliseconds.
      Path - Denotes a path identifier to specify a particular endpoint at the receiving node.
      Data - A ByteArray of data to pass. Do not pass >100KB. Pass Null if not required.
  • WearableAsset
    Methods:
    • CreateFromBitmap (bitmap As Bitmap) As Asset
      Creates an Asset to use from a Bitmap
    • CreateFromFile (Dir As String, Filename As String) As Asset
      Creates an Asset to use from a File
    • Info
      This method doesn't do anything, it is here purely for informational purposes.
      An asset is used to send a binary blob of data such as an image.
      You attach an asset to a DataItem.
      The system takes care of conserving bluetooth by caching large assets to avoid re-transmission.
  • WearableDataLayer
    Events:
    • BitmapResult (Tag As String, Result As Bitmap)
    • Connected ( As )
    • ConnectionFailed (ErrorCode As Int, Reason As String)
    • ConnectionSuspended (Reason As String)
    • DataChanged (ChangedItems As Map, DeletedItems As Map)
    • DataMapAdded (Success As Boolean)
    • DataMapDeleted (Path as string As , Success As Boolean)
    • DataMapResults (Success As Boolean, Results As Map)
    • FileResult (Tag As String, Dir As String, Filename As String, Success As Boolean)
    • LocalNodeIDResult (Success As Boolean, NodeID As String, NodeDisplayName As String)
    • MessageReceived (SourceNodeID As String, RequestID As Int, msgPath As String, Data As String)
    • MessageSent (Success As Boolean)
    • NodeResults (Results As List)
    • PeerConnected (ID As Int, DisplayName As String)
    Fields:
    • message As Message
    Methods:
    • AddDataMap (Path As String, dataMap As DataMap)
      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
      Will call DatamapAdded() once complete returning the path for Identification and the success
      Also triggers DataChanged() event if new information is added
    • ClearCallingIdentity
    • Connect
      Connects the Google Play services client (required for the Data Layer to work)
      The _onConnected event will raise once the connection is successful.
      Do NOT attempt to use the Data Layer until the connection is successful
      Make sure you disconnect the client once done (probably best to do this in Activity_Pause()
    • DeleteDataMap (Path As String)
      Deletes a DataMap
      Path - The path which the DataMap resides.
      Calls DataMapDeleted() Event if present, with the success of the action
    • Disconnect
      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
      Returns 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

      The results will be returned in the DataLayer_DataMapResults() event
    • GetBitmapFromAsset (tag As String, asset As Asset)
      Gets a Bitmap from an Asset
      Tag - a Tag used to identify the request in the resulting callback
      Asset - the Asset object to extract the File from
      Result returned in BitmapResult() callback
    • GetConnectedNodes
      Get a list of the connected Nodes (Devices)
      The returned List will contains a Map for each node.
      The map will then contains 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)
      ToString - A string representation of the full Node object, used mainly for my testing

      Result returned in NodeResults() Event
    • GetDataMap (Path As String, Tag As String)
      Gets an existing DataMap
      Path - the path that the DataMap resides
      Tag - a tag that is passed through to the results to make the result set identifiable
      If there is more than one DataMap with the same Path present on the Wear network. e.g. from different Nodes.
      All the DataMaps with that name will be returned.
      Use GetDataMap2 to specify a Node to narrow down a specific DataMap.
      Results are returned in DatamapResults() Event
    • GetDataMap2 (NodeID As String, Path As String, Tag As String)
      Similar to GetDataMap but allows you to specify a NodeID.
    • GetFileFromAsset (tag As String, asset As Asset, TargetDir As String, TargetFilename As String)
      Gets a File from an Asset
      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
      Result returned in FileResult() callback
    • Initialize (Eventname As String)
      Initializes the object.
      Note: this library requires Android 4.3 (API18) or above
    • LocalNodeID
      Gets the NodeID of the local Device
      Result returned in LocalNodeIDResult() event
    • RestoreCallingIdentity
  • WearableDataMap
    Methods:
    • Clear
      Clears all previously added data items from the DataMap
    • ContainsKey (Key As String) As Boolean
      Checks if the given key is contained in the DataMap.
      Returns True if the key is present
    • Get (Key As String) As Object
      Returns the DataMap entry with the given Key as an Object
    • GetAsset (Key As String) As Asset
      Gets an Asset data item from the DataMap
      Key - The reference as set in in the PutAsset() method
    • GetBoolean (Key As String) As Boolean
      Gets a Boolean data item from the DataMap
      Key - The reference as set in in the PutBoolean() method
    • GetByte (Key As String) As Byte
      Gets a Byte data item from the DataMap
      Key - The reference as set in in the PutByte() method
    • GetByteArray (Key As String) As Byte[]
      Gets a Byte Array data item from the DataMap
      Key - The reference as set in in the PutByteArray() method
    • GetDouble (Key As String) As Double
      Gets a Double data item from the DataMap
      Key - The reference as set in in the PutDouble() method
    • GetFloat (Key As String) As Float
      Gets a Float data item from the DataMap
      Key - The reference as set in in the PutFloat() method
    • GetFloatArray (Key As String) As Float[]
      Gets a Float Array data item from the DataMap
      Key - The reference as set in in the PutFloatArray() method
    • GetInt (Key As String) As Int
      Gets an Int data item from the DataMap
      Key - The reference as set in in the PutInt() method
    • GetLong (Key As String) As Long
      Gets a Long data item from the DataMap
      Key - The reference as set in in the PutLong() method
    • GetLongArray (Key As String) As Long[]
      Gets a Long Array data item from the DataMap
      Key - The reference as set in in the PutLongArray() method
    • GetString (Key As String) As String
      Gets a String data item from the DataMap
      Key - The reference as set in in the PutString() method
    • GetStringArray (Key As String) As String[]
      Gets a StringArray data item from the DataMap
      Key - The reference as set in in the PutStringArray method
    • Initialize
      Initializes the object.
      No Eventname is required. The DataLayer Eventname is used.
    • IsInitialized As Boolean
    • PutAsset (Key As String, Asset As Asset)
      Adds an Asset data item to the DataMap
      Key - a key used to reference the data item
      Asset - the Asset object to pass.
    • PutBoolean (Key As String, Val As Boolean)
      Adds a Boolean data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutByte (Key As String, Val As Byte)
      Adds a Byte data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutByteArray (Key As String, Val() As Byte)
      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 String, Val As Double)
      Adds a Double data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutFloat (Key As String, Val As Float)
      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 String, Val() As Float)
      Adds a Float Array data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutInt (Key As String, Val As Int)
      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 String, Val As Long)
      Adds a Long data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutLongArray (Key As String, Val() As Long)
      Adds a Long Array data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutString (Key As String, Val As String)
      Adds a String data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • PutStringArray (Key As String, Val() As String)
      Adds a String Array data item to the DataMap
      Key - a key used to reference the data item
      Val - the value to set to.
    • Remove (Key As String)
      Removes an item from the DataMap with the given Key
    • Size As Int
      Returns the number of Key-Value pairs currently in the DataMap
    • isEmpty As Boolean
      Return True if the DataMap is currently empty
    • toByteArray As Byte[]
      Returns the DataMap as a ByteArray
    • toString As String
      Returns a string representation of the DataMap
  • WearableListener
    Events:
    • DataChanged (ChangedItems As Map, DeletedItems As Map)
    • MessageReceived (SourceNodeID As String, RequestID As Int, msgPath As String, Data As String)
    Methods:
    • HandleIntent (StartingIntent As IntentWrapper) As Boolean
      Used to handle the starting intent when using static listeners.
      Will call the following events:
      _MessageReceived - When a message is received
      _DataChanged - When a DataMap is changed on the Wear Network
    • Initialize (EventName As String)
      initilizes the object and set the EventName for callback events

To Be Continued.............
 

Attachments

  • WearableDataLayer.zip
    30.8 KB · Views: 505

barx

Well-Known Member
Licensed User
Longtime User
Hi Barx
That's what I thought - so did just what you suggested again, but I still get this error during compiling of the Dynamic example (no mod's - just your code), I have also attached the manifest from the mobile app. The wearable app compiles no problem. Sorry to be a pain - I really appreciate your efforts

Ph1lj
Ah, that one is different. That one says the wearable_app_desc.xml file is missing. If it's not set as read only, the compiler will delete it
 

barx

Well-Known Member
Licensed User
Longtime User
OK - got it now, all works

Thanks
Like, like, like, like, like, lol

It's isn't the easiest system to work with, but unfortunately it is the card we have been dealt.....

Glad to hear you got something working ;)
 

canalrun

Well-Known Member
Licensed User
Longtime User
< Solved >
Thanks barx

I recompiled the static and dynamic wearable apps, moved the APKs to their raw directories, and recompiled/installed the mobile apps. It worked.

I also found your earlier post about setting up the debugger for the wearable device. Thank you for that.

Thanks for this library. I'm ready to start really playing :)

--------

Hello,
Thanks for the Wearable Data Layer library.
I just got a Samsung Gear Live (Android Wear 5.02) and I want to play with developing wearable apps using B4A.

I'm trying your two examples, completely unchanged, in post #2 of this thread – both static and dynamic. After I changed the AdditionalRes path, it compiled (B4A 4.3) and installed to my Nexus 5 (Android 5.1) without problems. I had to compile the Mobile B4A, but I use your wearable APK as is since it's already present in the Raw directory.

I notice it takes two or three minutes for the watch app to appear on the watch. Is this normal? I usually have to check "Start" two or three times before it finally shows up.

Once it shows up, I tap on it, for the Static I see the toast message "Example Starting", for the Dynamic I see the green "Listening" page. Back on the Nexus 5 I enter a short string like "asdf" and press "Send". Nothing appears on the Watch. I've tried with the black (off) screen showing, clock face showing, and menus showing, or "Listen" page showing for the Dynamic. From the code it looks like I'm supposed to see a toast message with the string data on the watch - Nada.

The B4A log for the Nexus 5 shows "Message Sent" when I press the Send button. I haven't figured out how to set up the debugger for the watch.

I've downloaded apps from Google Play, like calculators, and they appear to work correctly.

It seems like it works, except for the data transfer. Any hints or suggestions?

Thanks,
Barry.
 
Last edited:

potman100

Active Member
Licensed User
Longtime User
Hi barx

Can you tell me if this will run under B4J 3.82, I have been trying to get the examples working but
when I open them, I get a popup saying that this file is from a later version, and also as soon
as I open them Java.exe consumes 98% cpu.

I can't compile either as the compilor just stops at "Convert byte code - optimized dex", java.exe just starts
to eat memory and eventually fails.

Any Idea's ?

Regards

Potman
 

barx

Well-Known Member
Licensed User
Longtime User
< Solved >
Thanks barx

I recompiled the static and dynamic wearable apps, moved the APKs to their raw directories, and recompiled/installed the mobile apps. It worked.

I also found your earlier post about setting up the debugger for the wearable device. Thank you for that.

Thanks for this library. I'm ready to start really playing :)

--------

Hello,
Thanks for the Wearable Data Layer library.
I just got a Samsung Gear Live (Android Wear 5.02) and I want to play with developing wearable apps using B4A.

I'm trying your two examples, completely unchanged, in post #2 of this thread – both static and dynamic. After I changed the AdditionalRes path, it compiled (B4A 4.3) and installed to my Nexus 5 (Android 5.1) without problems. I had to compile the Mobile B4A, but I use your wearable APK as is since it's already present in the Raw directory.

I notice it takes two or three minutes for the watch app to appear on the watch. Is this normal? I usually have to check "Start" two or three times before it finally shows up.

Once it shows up, I tap on it, for the Static I see the toast message "Example Starting", for the Dynamic I see the green "Listening" page. Back on the Nexus 5 I enter a short string like "asdf" and press "Send". Nothing appears on the Watch. I've tried with the black (off) screen showing, clock face showing, and menus showing, or "Listen" page showing for the Dynamic. From the code it looks like I'm supposed to see a toast message with the string data on the watch - Nada.

The B4A log for the Nexus 5 shows "Message Sent" when I press the Send button. I haven't figured out how to set up the debugger for the watch.

I've downloaded apps from Google Play, like calculators, and they appear to work correctly.

It seems like it works, except for the data transfer. Any hints or suggestions?

Thanks,
Barry.
Sorry for not replying, I read this thread at work with the intention of answering when I got home........An forgot all about it :oops:
 

barx

Well-Known Member
Licensed User
Longtime User
Hi barx

Can you tell me if this will run under B4J 3.82, I have been trying to get the examples working but
when I open them, I get a popup saying that this file is from a later version, and also as soon
as I open them Java.exe consumes 98% cpu.

I can't compile either as the compilor just stops at "Convert byte code - optimized dex", java.exe just starts
to eat memory and eventually fails.

Any Idea's ?

Regards

Potman
I haven't really used b4j but I cannot see how it can work in it. It realies on things that simply are not available in b4a. for example, the google play service lib, the andrdoid wear device connection...
 

canalrun

Well-Known Member
Licensed User
Longtime User
Hello,
For my first test example I want to write something similar to your Dynamic Message example but using DataLayers.

I see the event documentation for:
  • DataChanged (ChangedItems As Map, DeletedItems As Map)

What do the Key/Value pairs represent for the two Maps? I did not see this in the documentation.

Thanks,
Barry.
 

barx

Well-Known Member
Licensed User
Longtime User
Hi

Sorry, I mean't B4A 3.82.

Regards

Potman
The library itself will work in b4a 3.82 but as stated the examples were written in a later version. 4.00 i think. I don't think it will be backwards compatible.
 

barx

Well-Known Member
Licensed User
Longtime User
Hello,
For my first test example I want to write something similar to your Dynamic Message example but using DataLayers.

I see the event documentation for:
  • DataChanged (ChangedItems As Map, DeletedItems As Map)

What do the Key/Value pairs represent for the two Maps? I did not see this in the documentation.

Thanks,
Barry.
Hi @canalrun

The key will be the path (as specified when you add or delete the dataMap) and the value will be the dataMap itself.
 

potman100

Active Member
Licensed User
Longtime User
Hi barx

Thanks for the info, but still having the same issue, If I create a new app, then add references to JavaObject and WearableDataLayer all seems ok, but
as soon as I save the app, task manager shows that java.exe starts to consume 80% cpu and eats memory > 1 gig in a few seconds.

If I close the app and reopen it java.exe starts eating cpu and memory as soon as the app opens, without any compile, just opening.

Any Idea's ?

Thanks for your time by the way.

Regards

Potman
 

barx

Well-Known Member
Licensed User
Longtime User
Hi barx

Thanks for the info, but still having the same issue, If I create a new app, then add references to JavaObject and WearableDataLayer all seems ok, but
as soon as I save the app, task manager shows that java.exe starts to consume 80% cpu and eats memory > 1 gig in a few seconds.

If I close the app and reopen it java.exe starts eating cpu and memory as soon as the app opens, without any compile, just opening.

Any Idea's ?

Thanks for your time by the way.

Regards

Potman
I don't i'm afraid, I've seen that before. And it only happens when you add the WearableDataLayer lib? Or is it only when WDL AND JavaObject are both enabled?
 

potman100

Active Member
Licensed User
Longtime User
Hi

I've just created 2 apps, I added just a ref to the javaobject and saved it and all is fine.
I closed and opened it and and all was fine.

I Created the second app and added a ref to the WDL and as soon as I saved it, java.exe started to eat CPU and Memory.
I closed and Opened it and soon as it opened Java.exe started to eat CPU and Memory again, without doing anything, just opening it.

Only seems to be when I add the WDL.

Regards

Potman
 

canalrun

Well-Known Member
Licensed User
Longtime User
Hello,
I'm having trouble with Bitmap Assets. The following code generates an exception on the marked line:

B4X:
Sub SelSmile(bm As Bitmap)
  Log("ivSml_Click")
 
  If (DMPath <> "") Then
    DM.PutString("tst", "Test String")
    Log("  PutString")
   
    Log("  GetString: " & DM.GetString("tst"))

    Dim dma As WearableAsset

    DM.PutAsset(DMKey, dma.CreateFromBitmap(bm))
    Log("  PutAsset")
   
    DL.GetBitmapFromAsset(DMKey, DM.GetAsset(DMKey)) ' <-- <-- <--
    Log("  GetAsset")
  End If
 
  ivChosen.Bitmap = bm
 
  Log("  Key: " & DMKey & ", " & DM.ContainsKey(DMKey))
End Sub

B4X:
ivSml_Click
  PutString
  GetString: Test String
  PutAsset
java.lang.IllegalArgumentException: invalid asset
    at com.google.android.gms.wearable.internal.zzu.zza(Unknown Source)
    at com.google.android.gms.wearable.internal.zzu.getFdForAsset(Unknown Source)
    at barxdroid.wearabledatalayer.WearableDataLayer.GetBitmapFromAsset(WearableDataLayer.java:498)
    at canalrun.wear.dmex.main._selsmile(main.java:784)
    at canalrun.wear.dmex.main._dl_datamapresults(main.java:561)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA$3.run(BA.java:332)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

The code is almost directly derived from your Dynamic Example. The bitmap, bm, shows in the image view correctly if I comment out the IF block - so I know it's valid. The put and get strings above work properly. The error is telling me that the asset is not a valid bitmap.

Any idea the problem might be?

Thanks,
Barry.
 

canalrun

Well-Known Member
Licensed User
Longtime User
Hello,
I am also wondering what the exact meaning of the WearableDataLayer/DataChanged event is?

I have a mobile and a watch communicating back and forth using DataMaps. They both reference the same map using their DL_DataMapResults event.

If I change one of the Values associated with a Key in the DataMap, I don't get a DataChanged event. However, if I call DeleteDataMap I get the DataChanged event twice – once for ChgItm > 0, and once for DelItm > 0.

I had expected to get a DataChanged event if I modify the Value associated with a Key from either device. This is the only way two devices would seem to be able to communicate via DataMaps.

What am I missing?

Thanks,
Barry.
 

barx

Well-Known Member
Licensed User
Longtime User
Hello,
I'm having trouble with Bitmap Assets. The following code generates an exception on the marked line:

B4X:
Sub SelSmile(bm As Bitmap)
  Log("ivSml_Click")

  If (DMPath <> "") Then
    DM.PutString("tst", "Test String")
    Log("  PutString")
 
    Log("  GetString: " & DM.GetString("tst"))

    Dim dma As WearableAsset

    DM.PutAsset(DMKey, dma.CreateFromBitmap(bm))
    Log("  PutAsset")
 
    DL.GetBitmapFromAsset(DMKey, DM.GetAsset(DMKey)) ' <-- <-- <--
    Log("  GetAsset")
  End If

  ivChosen.Bitmap = bm

  Log("  Key: " & DMKey & ", " & DM.ContainsKey(DMKey))
End Sub

B4X:
ivSml_Click
  PutString
  GetString: Test String
  PutAsset
java.lang.IllegalArgumentException: invalid asset
    at com.google.android.gms.wearable.internal.zzu.zza(Unknown Source)
    at com.google.android.gms.wearable.internal.zzu.getFdForAsset(Unknown Source)
    at barxdroid.wearabledatalayer.WearableDataLayer.GetBitmapFromAsset(WearableDataLayer.java:498)
    at canalrun.wear.dmex.main._selsmile(main.java:784)
    at canalrun.wear.dmex.main._dl_datamapresults(main.java:561)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA$3.run(BA.java:332)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

The code is almost directly derived from your Dynamic Example. The bitmap, bm, shows in the image view correctly if I comment out the IF block - so I know it's valid. The put and get strings above work properly. The error is telling me that the asset is not a valid bitmap.

Any idea the problem might be?

Thanks,
Barry.


I've said it before and I'll say it again. This is not an easy system to work with. It has caused me some real headaches. I've tried to make the lib as easy as poss, but the way google have implemented it, it wasn't easy. From looking at the code above I will give some pointers. I will be making an attempt to properly document the library soon.

So, you build the DataMap (DM) adding text and an Asset as a bitmap. Good so far. Once you have built the DataMap, you must add it to the DataLayer

B4X:
DataLayer1.AddDataMap("/aPath", DM)

Doing this will sync the DataMap onto the Wear Network and thus trigger the DataChanged event on the connected device(s).

You can then access the synced DataMap from the DataChanged event and use the GetBitmapFromAsset method.

I will add a link shortly to the projects I have been using to test the library as I developed it. The code inside is a little scrappy but it may help you follow the flow...


https://dl.dropboxusercontent.com/u/53092305/WearTest.ziphttps://dl.dropboxusercontent.com/u/53092305/WearTest.zip
 
Last edited:

barx

Well-Known Member
Licensed User
Longtime User
Hello,
I am also wondering what the exact meaning of the WearableDataLayer/DataChanged event is?

I have a mobile and a watch communicating back and forth using DataMaps. They both reference the same map using their DL_DataMapResults event.

If I change one of the Values associated with a Key in the DataMap, I don't get a DataChanged event. However, if I call DeleteDataMap I get the DataChanged event twice – once for ChgItm > 0, and once for DelItm > 0.

I had expected to get a DataChanged event if I modify the Value associated with a Key from either device. This is the only way two devices would seem to be able to communicate via DataMaps.

What am I missing?

Thanks,
Barry.
The DataChanged event will trigger every time a DataMap (with changes) is added to the DataLayer. If the data is the same, the event won't trigger. If you want it to trigger every time the data is commited it is advised to add a timestamp on each commit...
 

canalrun

Well-Known Member
Licensed User
Longtime User
I've said it before and I'll say it again. This is not an easy system to work with....

Doing this will sync the DataMap onto the Wear Network and thus trigger the DataChanged event on the connected device(s). You can then access the synced DataMap from the DataChanged event and use the GetBitmapFromAsset method.

Hello,
I think you hit the nail on the head – I'll have to give this a try. I was using the original DataMap variable. I think I need to use the new DataMap variable that is returned in the DataChanged event.

I agree, Google could put a little more thought into their libraries to make them easier to work with.

I think using messages to send "commands" is a little more in line with what I need to do. I am building a test app based on your Dynamic example.

Barry.
 

canalrun

Well-Known Member
Licensed User
Longtime User
*** Example App ***

Hello,
I made an example app, based on barx's, Dynamic Message example.

My example adds bidirectional messages and really great graphics :)

upload_2015-5-28_15-42-5.png


On both the mobile and wearable devices you'll see a screen that looks something like this. Click one of the smiley's in the four corners and the smiley in the middle will be replaced by the selected one. Also a message will be sent to all connected devices to update their middle smiley with the selected one.

One of the four smiley's can be selected on either the phone or wearable.

I used B4A version 4.3 to develop this example. I have included both mobile and wearable projects with source.

  1. With no devices attached via the B4A Bridge or USB, compile the wearable.b4a app in Release mode. You will get a "No devices found" error during compile. Just ignore this error, closing the dialogs – the APK will be built.

  2. Copy the crwearable.apk file from the wearable\Objects directory to the mobile\Objects\res\raw directory. Notice the xml and raw directories in the mobile\Objects\res folder. The xml directory contains a script that will direct Android how to install the wearable app. The raw directory contains the APK that will be installed to the wearable device when the mobile APK is installed on the mobile device. (I have included BuildActions in the crmobile.b4a file to temporarily make these two folders read-only so it is not necessary to manually make the xml and raw folders read-only.)

  3. Attach the mobile device to the B4A bridge then compile the crmobile.b4a app. When the app installs to the mobile device, the wearable app will also be installed to the wearable device. This might be peculiar to my Samsung Gear Live watch, but installation of the wearable app sometimes takes 90 seconds or so. On the wearable device from the clock face click to show the menu, click Start. My example app will show up as "CR Wear Example". I usually get inpatient and have to do this two or three times before it shows up.

Barry.
 

Attachments

  • CRWear.zip
    44.3 KB · Views: 212
Top