Sending message from wearable to phone: onMessageRecieved not called - android

So I have a connected Wear Emulator and a android phone to test.
Sending data maps from phone to wearable works fine.
Now I want to send a message from the wearable to the phone.
I've tried this with AsyncTask and without it. Messages are being successfully sent in both cases, but the message never reaches my phone.
My application IDs are the same.
Here's my code:
//Wear
//Try with Async
inner class requestTokenTask : AsyncTask<Void?, Void?, Void?>() {
override fun doInBackground(vararg params: Void?): Void? {
Wearable.getMessageClient(this).sendMessage(_connectedNode.toString(), "/requesttoken", null)
return null
}
override fun onPostExecute(aVoid: Void?) {
super.onPostExecute(aVoid)
Log.d(TAG, "Message sent: $aVoid")
}
}
//Try without async
fun requestToken() {
if(_connectedNode?.id != null){
val sendTask: Task<*> = Wearable.getMessageClient(this).sendMessage(
_connectedNode!!.id!!,
"/requesttoken",
null
).apply {
addOnSuccessListener {
Log.d(TAG, "Message sent: $it")
}
addOnFailureListener {
Log.d(TAG, "Message NOT sent, error: $it")
}
}
}
}
Handheld code:
public override fun onResume() {
super.onResume()
Wearable.getDataClient(this).addListener(this)
Wearable.getMessageClient(this).addListener(this)
Wearable.getCapabilityClient(this)
.addListener(this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE)
}
override fun onMessageReceived(messageEvent: MessageEvent) {
Log.d(TAG, "onMessageReceived()")
//Receive the message from wear
if (messageEvent.path.equals("/requesttoken")) {
//Do stuff
}
}
Manifest part:
<activity
android:name=".wear.WearableActivity"
android:theme="#style/Theme.Transparent">
<intent-filter>
<action
android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data android:scheme="wear" android:host="*" android:pathPrefix="/token"/>
</intent-filter>
</activity>
UPDATE: Just found out that "BIND_LISTENER" is deprecated, tried again with removing it and adding "MESSAGE_RECIEVED" instead, but it's still not working.

I tried another way with Broadcast Recievers with this tutorial and the communication now works in both ways

Related

WearableListenerService onCreate and onDataChanged not getting called

I'm trying to send data using the DataClient from a phone to a watch.
Things I looked out for:
same package name
no build flavors on both modules
added service to the wear modules manifest
same path prefix
same signing config
I tried this sample project and copied parts over to my project. I just can't find any issues with it.
The sample project ran fine on my hardware, interestingly enough it wasn't working in the emulator. Therefore I tested my app also only with my hardware. (Pixel 6 Pro & Pixel Watch)
The sending data part seems to be working, as it behaves the same way as the sample project does.
How I send data from the phone:
class WearDataManager(val context: Context) {
private val dataClient by lazy { Wearable.getDataClient(context) }
companion object {
private const val CLIENTS_PATH = "/clients"
private const val CLIENT_LIST_KEY = "clientlist"
}
fun sendClientList(clientList: MutableList<String>) {
GlobalScope.launch {
try {
val request = PutDataMapRequest.create(CLIENTS_PATH).apply {
dataMap.putStringArray(CLIENT_LIST_KEY, arrayOf("clientList, test"))
}
.asPutDataRequest()
.setUrgent()
val result = dataClient.putDataItem(request).await()
Log.d("TAG", "DataItem saved: $result")
} catch (cancellationException: CancellationException) {
throw cancellationException
} catch (exception: Exception) {
Log.d("TAG", "Saving DataItem failed: $exception")
}
}
}
}
This is how I'm receiving data on the watch:
class WearableListenerService: WearableListenerService() {
companion object {
const val CLIENTS_PATH = "/clients"
}
override fun onCreate() {
super.onCreate()
Log.d("testing", "STARTED SERVICE")
}
override fun onDataChanged(dataEvents: DataEventBuffer) {
super.onDataChanged(dataEvents)
Log.d("testing", "RECEIVED $dataEvents")
}
}
Surprisingly "STARTED SERVICE" does not appear in the log when I start the app on the watch. For my understanding that means that the system isn't aware of the listeners existance and didn't register it. So something must be wrong with the manifest below.
This is the service inside the manifest on the watch:
<service android:name=".wear.communication.WearableListenerService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:host="*"
android:pathPrefix="/clients"
android:scheme="wear" />
</intent-filter>
</service>
What am I missing here?
Turns out the sending part was the culprit after all. Be careful what scope you use or if you even want to use one at all. This function is being called inside of a worker in my code so it isn't an issue.
I completely modified the demo project above and with the help of this I found out why it wasn't working.
This is the working solution:
fun sendClientList(clientList: MutableList<String>) {
val request = PutDataMapRequest.create(CLIENTS_PATH).apply {
dataMap.putStringArray(CLIENT_LIST_KEY, arrayOf(clientList.joinToString()))
}
.asPutDataRequest()
.setUrgent()
val result = dataClient.putDataItem(request)
Log.d("TAG", "DataItem saved: $result")
}

Flutter receive share intent text as Stream

I'm testing some functions with flutter to try to find out if I'm able to handle it and right now it doesn't seem that I would be able to make it.
I've set up a app which should be able to handle incoming text from android intents. With that text I've wanted to open a specific screen of my app and load specific data into the screen.
I've tried so many different approaches that I can't even remember when it worked best and what went wrong.
Right now I have the following code.
AndroidManifest.xml
<application
android:name=".MyApplication"
android:label="My cool App"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MyFlutterActivity"
android:launchMode="standard"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
MyApplication.kt
class MyApplication : FlutterApplication(), PluginRegistrantCallback {
lateinit var flutterEngine: FlutterEngine
override fun registerWith(registry: PluginRegistry) {
FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
}
override fun onCreate() {
super.onCreate()
// Instantiate a FlutterEngine.
flutterEngine = FlutterEngine(this)
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
// Cache the FlutterEngine to be used by FlutterActivity.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine)
FlutterFirebaseMessagingService.setPluginRegistrant(this)
}
As you can see I'm also using the FlutterFirebaseMessagingService to receive notifications, which I'm right now not already sure if it is still working as it already was.
FlutterActivity.kt
class MyFlutterActivity : FlutterActivity() {
private var sharedText: String? = null
override fun provideFlutterEngine(context: Context): FlutterEngine? {
return FlutterEngineCache.getInstance().get("my_engine_id")
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
// Use the GeneratedPluginRegistrant to add every plugin that's in the pubspec.
//GeneratedPluginRegistrant.registerWith(flutterEngine)
handleShareIntent()
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "com.example.app.shared.data")
.setMethodCallHandler {call: MethodCall , result: MethodChannel.Result ->
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText)
sharedText = null
}
}
}
fun handleShareIntent() {
//val intent = getIntent()
val action = intent.action
val type = intent.type
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent)
}
}
}
fun handleSendText(intent: Intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
}
main.dart
static const platform =
const MethodChannel('com.example.app.shared.data');
static Stream<String> get sharedData {
return new Stream<String>.fromFuture(
platform.invokeMethod("getSharedText"));
}
//... inside build
StreamProvider<String>.value(
lazy: true,
value: sharedData,
),
// .. handle inside build
final String sharedData = Provider.of<String>(context);
// .. handle shared Data and open Screen..
I've tried to log every step to find out what's not working.
So I connected my android phone and tried to debug, but didn't found a step where to handle the incoming data, even if the text is successfully handled inside the "handleSendText" method of the FlutterAcitivity.kt.
What even more confused me is, that if i save a dart file / press hot reload, my breakpoint inside the sharedData getter of the main.dart is getting called and from there everything works as it should.
But why do I have to hot reload where it should start itself instead.
Am I'm missing anything or doing wrong at this point?
Any help appreciated.

Google Nearby - Connections API - Discovery not working

so recently my friends and i thought about creating an app that allows somewhat of realtime communication between the connected devices, without the need of a webserver. More explicitily, it should be an app, where a single device (master/host) create a game/session and multiple devices (slaves/clients) can join. after establishing all necessary connections (4-5 clients), the host should be able to broadcast data to the clients. Hence i researched a bit and if i understand it correctly the best guess for android are either the WiFi direct oder the google nearby connections api.
Q1. Is this the most simple approach to the desired goal ? or is this already too deep?
So i played a bit around with the connections api, i made a simple application and just used the code from the Nearby Documentation. Since im new to Kotlin, it could also be a rather simple mistake, however after a 2 hours, i swapped back to java with the same error. when the clients try to discover the host, they triggered their OnFailureListener. I tried to search for a solution online (including SO), but i could not find any useful information.
Im testing the application on a HTC ONE M8 and a Samsung Galaxy S7. To Ensure the Nearby Connection API features should work I also downloaded 2 example apps and those worked just fine. I tried how these handled the usage of the api but could not find the important part.
Q2. Where do i use the API wrong ? Or is it really just a error in the coding ?
MainActivity.kt
private const val TAG = android.R.attr.packageNames.toString() + "/Filter"
class MainActivity : AppCompatActivity() {
private lateinit var connectionClient : ConnectionsClient
private val payloadCallback = object : PayloadCallback() {
override fun onPayloadReceived(p0: String, p1: Payload) {
Toast.makeText(applicationContext, "Payload Received", Toast.LENGTH_SHORT).show()
}
override fun onPayloadTransferUpdate(p0: String, p1: PayloadTransferUpdate) {
Toast.makeText(applicationContext, "Payload Transfer Update", Toast.LENGTH_SHORT).show()
}
}
private val connPoint = object : ConnectionLifecycleCallback() {
override fun onConnectionInitiated(p0: String, p1: ConnectionInfo) {
connectionClient.acceptConnection(p0, payloadCallback)
Log.i(TAG, "OnConnectionInitiated")
}
override fun onConnectionResult(p0: String, p1: ConnectionResolution) {
when(p1.status.statusCode){
ConnectionsStatusCodes.STATUS_OK -> Log.i(TAG, "ConnectionsStatusCodes STATUS_OK")
ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED -> Log.i(TAG, "ConnectionsStatusCodes STATUS_CONNECTION_REJECTED")
ConnectionsStatusCodes.STATUS_ERROR -> Log.i(TAG, "ConnectionsStatusCodes STATUS_ERROR")
else -> Log.i(TAG, "ConnectionsStatusCodes STATUS_UNKNOWN")
}
}
override fun onDisconnected(p0: String) {
Log.i(TAG, "onDisconnected $p0")
}
}
private val endPoint = object : EndpointDiscoveryCallback() {
override fun onEndpointFound(p0: String, p1: DiscoveredEndpointInfo) {
Log.i(TAG, "onEndpointFound ID: $p0 Name: ${p1.endpointName} ")
connectionClient.requestConnection(p1.endpointName, p0, connPoint)
.addOnSuccessListener {
Log.i(TAG, "OnSuccessListener requestConnection")
}
.addOnFailureListener {
Log.i(TAG, "OnFailureListener requestConnection")
}
}
override fun onEndpointLost(p0: String) {
Log.i(TAG, "$p0 disconnected")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
connectionClient = Nearby.getConnectionsClient(this.applicationContext)
//Toast.makeText(applicationContext, connectionClient.instanceId, Toast.LENGTH_SHORT).show()
setButtonOnClick()
}
override fun onStop() {
connectionClient.stopAllEndpoints()
connectionClient.stopAdvertising()
connectionClient.stopDiscovery()
super.onStop()
}
private fun setButtonOnClick(){
val create = findViewById<Button>(R.id.create_btn)
val join = findViewById<Button>(R.id.join_btn)
create.setOnClickListener{ _ -> CreateGroup()}
join.setOnClickListener{ _ -> JoinGroup()}
Log.i(TAG, "On Click Listener set")
}
private fun CreateGroup(){
Log.i(TAG, "Starting Advertising")
connectionClient
.startAdvertising(android.os.Build.MODEL,
packageName.toString(),
connPoint,
AdvertisingOptions.Builder().apply{
setStrategy(Strategy.P2P_CLUSTER)
}.build())
.addOnSuccessListener {
OnSuccessListener<Void> {
Log.i(TAG, "OnSuccessListener CreateGroup() was triggered")
}
}
.addOnFailureListener {
OnFailureListener {
Log.i(TAG, "OnFailureListener CreateGroup() was triggered")
}
}
}
private fun JoinGroup(){
Log.i(TAG, "Starting Discovering")
connectionClient.startDiscovery(packageName.toString(),
endPoint,
DiscoveryOptions.Builder().apply{
setStrategy(Strategy.P2P_CLUSTER)
}.build())
.addOnSuccessListener {
OnSuccessListener<Void> {
Log.i(TAG, "OnSuccessListener JoinGroup() was triggered")
}
}
.addOnFailureListener {
OnFailureListener {
Log.i(TAG, "OnSuccessListener JoinGroup() was triggered")
}
}
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testapplication">
<!-- Required for Nearby Connections -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Optional: only required for FILE payloads -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Okay, after figuring out how to correctly setup the Listeners using Kotlin i found out that i got the exception of a missing permission, 01-20 21:11:14.269 1058-1058/com.example.testapplication I/16843649/Filter: 8034: MISSING_PERMISSION_ACCESS_COARSE_LOCATION, which i thought was strange since its in the manifest. However i went to the normal app settings and turned on the permissions manually, and it works now.

Oreo: How to listen unlock event?

I want to do some work when user unlock their phone
I define a receiver in AndroidManifest.xml
<receiver
android:enabled="true"
android:name=".service.ScreenReceiver">
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
and Receiver
class ScreenReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
}
private fun checkClearSavedNote(context: Context) {
AppPref.getInstance(context).putString(AppPref.KEY_ID_CURRENT_NOTE, "")
Log.e("Quang", "clear note")
}
}
But it was not called when fired
I've tried using Service and registerBroadcastReceiver inside
and start it when application start
class MyApplication : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
instance = this
MultiDex.install(applicationContext)
try {
startService(Intent(this, NoteService::class.java))
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}
but it work only with Android API < 8.0 because background execution limit
You can set your targetSdk < 26 to leverage implicit broadcasts. Otherwise you have to change your design according to latest list of exempted broadcasts.

NotificationListenerService not created

Maybe stupid question, but I have already spent to many hours on this.
I have my Kotlin listener:
package pl.bmideas.michal.bmnotifier
public class MyNotificationListener : NotificationListenerService() {
private var apiService :BackendApi? = null;
override fun onCreate() {
Log.i("MyNotificationListener" , "Creating NotificationListenerService service")
super.onCreate()
(.........SOMETHING ELSE..............)
}
override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "DESTROING")
(.........SOMETHING ELSE..............)
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
val sbnInfo = StatusBarNotificationExtended(sbn)
Log.i(TAG, "REMOVED")
}
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.i(TAG, "RECIVED`")
(.........SOMETHING ELSE..............)
}
companion object {
var TAG = "MyNotificationListener"
}
}
and my config looks looks this:
<service
android:enabled="true"
android:name="pl.bmideas.michal.bmnotifier.MyNotificationListener"
android:label="#string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
I'm not doing anything special in Activity.
Yes - I've checked security option and my app has access to notifications.
Yes - I've tried pointing to service by dot instead of full package
In logcat I can only see:
12-23 12:56:54.989 889-889/? V/NotificationListeners: enabling notification listener for 0:
ComponentInfo{pl.bmideas.michal.bmnotifier/pl.bmideas.michal.bmnotifier.MyNotificationListener}
I cant get instance unless i will bidn to this service in Activity wchich creates the service but still I get no info in logcat about notifications.
Can you guys help?
Holly....
after rewriting this code to pure Java it works..... but why?

Categories

Resources