Sending React Native Android Events to JavaScript from a Service - android

I am trying to emit an event using DeviceEventManagerModule.RCTDeviceEventEmitter in React Native, but because I wish to call it from a Service, I don't know how to get the reactContext. My code looks like this:
class TimerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val reactContext = ???
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("tick", "tock");
}
}
If the essence of what I am trying to do is wrong I'm happy to change anything and everything.
For more context, what I'm trying to do is keep track of rest timers in-between sets at the gym. Full code can be found here. I wanted to add a page to display the currently running rest timer, where the state is being stored in TimerService.
I tried to cast applicationContext to ReactContext like:
(applicationContext as ReactApplicationContext)
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("tick", "tock");
But was given an error saying I can't cast ApplicationContext to ReactApplicationContext. I also tried to figure out how I could pass reactApplicationContext down to my Service, but got a bit stumped on trying to parcel it for an Intent.

Related

Running CameraX in a service in Android Studio with Kotlin

i want to create a class in Android Studio using Kotlin that runs Camera in background
class MyForegroundService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(1, notification)
// **************** I want to add camerax here *****************************
return START_STICKY
}
}
to run the camera in background can you help me please
Do you want to develop any ForegroundService for android?
Some answers already have been made on the Use of camera as ForegroundService. You can check the links below.
Camera frames in a service / background process
Grafika, a dumping ground for Android graphics & media hacks.

How to restart Android app within Espresso test?

I am using Espresso with Kotlin for the UI test automation. I am trying to find a proper way to restart the app during the test and start it again, so the test scenario is the following:
start the app, go to login page
force close the app and open it again (basically restart it)
check some stuff etc
The way our UI tests are organized:
there is a test class where I have rules
val intent = Intent(ApplicationProvider.getApplicationContext(), MainActivity::class.java)
.putExtra(UI_TEST_INTENT, true)
#get:Rule
val rule = ActivityScenarioRule<MainActivity>(intent)
there Before/After functions and tests functions in this class
What I want is to have generic restartApp function in separated class, let's say TestUtils and to be able to call it at any point of time, when is needed.
So far I didn't find a solution. There are some similar questions on stackoverflow, but I am not sure I understand how to work with the answers I found, like this:
with(activityRule) {
finishActivity()
launchActivity(null)
}
Since ActivityTestRule is deprecated and documentation asking to use ActivityScenarioRule, I tried this:
#get:Rule
val rule = ActivityScenarioRule<MainActivity>(intent)
private fun restart() {
rule.scenario.close()
rule.scenario.recreate()
}
but it gets java.lang.NullPointerException
another option is
private fun restart() {
pressBackUnconditionally()
Intents.release()
ActivityScenario.launch<MainActivity>(intent)
}
it works, app restarts but I can not interact with the app anymore, because for some reason there are two intents running now
Would be great to get an answer I can work with (I am quite new to Espresso)
Cheers
The solution is found:
private fun restart() {
Intents.release()
rule.scenario.close()
Intents.init()
ActivityScenario.launch<MainActivity>(intent)
}
Seems like the author's answer has some excess code. The following is enough
activityScenarioRule.scenario.close()
ActivityScenario.launch(YourActivity::class.java, null)

Autofill service enable via Activity Results API

I'm try to register an ActivityResultContract for android.provider.Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE using kotlin and AndroidX:
class AutofillContract() : ActivityResultContract<Any?,ActivityResult>() {
override fun createIntent(context: Context, input: Any?): Intent
= Intent(android.provider.Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult
= ActivityResult(resultCode, intent)
}
val afrl = registerForActivityResult(AutofillContract()) {
if (it.resultCode == RESULT_OK) ...
else ...
}
However, when I try to use it:
afrl.launch(AutofillContract().createIntent(this, null))
I get IllegalArgumentException: Can only use lower 16 bits for requestCode, which I presume was triggered by an internal startActivityForResult() call.
I haven't used a custom ActivityResultContract before, and although it seems simple it also seems a bit sketchy to me -- I'm not sure if regarding the input as irrelevant (Any?) is the way to go, but it does seem irrelevant in this case (the first version used Intent as the input type but there doesn't seem to be a point, and the problem, "Can only use lower 16 bits..." was the same).
I'm using androidx.activity:activity-ktx:1.2.0-alpha08.
As per this issue, you get that error when you are using an older version of Fragments.
You must also upgrade your version of Fragments to androidx.fragment:fragment-ktx:1.3.0-alpha08.

Start a FlutterActivity subclass using a cached engine

I'm currently adding a view developed using Flutter to an existing Android app. I have been following the tutorials found in the Flutter website and decided to used a cached engine in order to minimize the delay that users may experience when navigating to the Flutter portion of the app. In order to do so, you must launch your Flutter activity like
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(this) // this is a Context
)
After a while I need to wirte a method channel to communicate from the Flutter portion of the app back to the Android host app, so I followed the instructions found in another of Flutter's tutorials, where it is shown that the activity that implements the channel must extend FlutterActivity.
So my problem is that I'm not sure how to initialize this activity using a cached engine, since I obviously can't use FlutterActivity.withCachedEngine anymore. Has anyone solved this already?
After looking at FlutterActivity documentation I found the provideFlutterEngine method. The doc description clearly states that:
This hook is where a cached FlutterEngine should be provided, if a cached FlutterEngine is desired.
So the final implementation of my class looks like this now
class MyActivity : FlutterActivity() {
override fun provideFlutterEngine(context: Context): FlutterEngine? =
FlutterEngineCache.getInstance().get(FlutterConstants.ENGINE_ID)
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "my-channel")
.setMethodCallHandler { call, result ->
if (call.method == "my-method") {
myMethod()
result.success(null)
} else {
result.notImplemented()
}
}
}
private fun myMethod() {
// Do native stuff
}
}
And I simply start it writing startActivity(Intent(this, MyActivity::class.java))

Android - display In-app message natively

I would like my app tз display a notification of the incoming messages, but only when the application is active, similar to how many social apps do that.
I.e., the user has my messaging app open and he gets a notification slide in from top, within this Android application.
To my understanding, this is something that is called “in app messages” in Firebase.
However, I wouldn’t like to have firebase as a dependency, as I am not using any part of it: the notifications will be triggered by an open network connection that my app made.
I also so wouldn’t want to involve push notifications as I need this functionality only when the app is active.
What would be the best way to achieve this goal?
Basically what I am asking is how to make my own notification “bubble” in UI that shows up inside my app, similar to how it is done in messaging/dating apps (see Badoo, for example). Mainly I am wondering if there are any implemendations available that I could use or do I have to draw this stuff myself (using Fragments?)
It's a very broad question. So in broad strokes: Use some real time communications technology, such as sockets/websockets to listen for incoming messages, and hook up into lifecycle to start listening when the app moves into foreground (and stop when it moves out) [assuming that is the meaning of app being active - otherwise if you include foreground state, just start listening and don't unlisten) -
class MyListener : LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
listenForNotification()
//start listening
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
//stop listening
}
where listener would be something like this:
private suspend fun listenForNotification(){
withContext(Dispatchers.IO){
myApi.receive() {
println("this is my notification object: $it")
NotificationHelper.sendNotification($it.message)
}
}
}
And NotificationHelper would be based on Notification Manager to push local notifications (as you wanted them to slide from the top - look like any push notification). Pay close attention to the flags you use to send the notification to make sure it is received and processed by the currently opened activity (do more research on it, separate topic) https://developer.android.com/reference/android/app/NotificationManager
In that same activity use OnNewIntent to receive user's action of tapping on the notification and then do whatever you want to do with it.
Alternatively, do not use local notification but just develop your own UI where you would display these things messaging style. (edit: for example, like this - link. Another one for actually showing notifications without using Notifications lib -link
Or a combination of both local notifications and the above example.
Edit:
*You can also use Firebase messaging to display messages locally.* Yes you would still need a firebase json to init the app, but after that you can construct your messages locally and display them, so it a very lightweight dependency on two libs and aside from initializing you won't need anything else from the firebase server.
Below is an example with two types of messages, card and banner. And of course you can just take the full code on GitHub and extract the part you need and modify it as needed. (the method used here is public for testing the appearance of the message locally - I don't see anything wrong with using it as a vehicle to deliver local notifications, but again the option to take the code and modify is always there)
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.firebase.FirebaseApp
import com.google.firebase.inappmessaging.MessagesProto
import com.google.firebase.inappmessaging.display.FirebaseInAppMessagingDisplay
import com.google.firebase.inappmessaging.model.*
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
companion object {
val whiteHex = "#ffffff"
val magHex = "#9C27B0"
val appUrl ="app://open.my.app"
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
val action: String? = intent?.action
val data: Uri? = intent?.data
data?.let {
helloTextView.text ="You just clicked from Firebase Message"
return
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
FirebaseApp.initializeApp(this)
val text = Text.builder()
.setHexColor(whiteHex)
.setText("Local Firebase Message Body")
.build()
val title = Text.builder()
.setHexColor(whiteHex)
.setText("Local Firebase Message Title")
.build()
val imageData = ImageData.builder()
.setImageUrl("https://homepages.cae.wisc.edu/~ece533/images/frymire.png")
.build()
val button = Button.builder()
.setButtonHexColor(whiteHex).setText(text).build()
val campaignMeta = CampaignMetadata("S", "D", true)
val primaryAction = Action.builder()
.setActionUrl(appUrl)
.setButton(button)
.build()
val fmessage = CardMessage.builder()
.setPrimaryAction(primaryAction)
.setBackgroundHexColor(magHex)
.setPortraitImageData(imageData)
.setTitle(title).build(campaignMeta)
val bannerMessage = BannerMessage.builder()
.setAction(primaryAction)
.setImageData(imageData)
.setBackgroundHexColor(magHex)
.setBody(text)
.setTitle(title).build(campaignMeta)
FirebaseInAppMessagingDisplay
.getInstance()
.testMessage(this, bannerMessage, null)
}
}
In build.gradle make sure to add:
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.firebase:firebase-inappmessaging-display:19.0.2'
and intent filter into manifest (to process click on the message)
<data android:scheme="app" android:host="open.my.app" />
also modify launchMode to singleTop to process the click within the same instance of the activity:
<activity android:name=".MainActivity"
android:launchMode="singleTop"
>
and apply
apply plugin: 'com.google.gms.google-services'
The result:
Card message:
Banner message and updating text in response to clicking on the banner:
Added project into GitHub if you are interested - project link. Must add your own google-services.json for firebase (to be able to init the engine only)

Categories

Resources