Make Buffer emit values before specified timestamp? - android

I have logic for 3 button clicks and I want to add one more action on first and second clicks immediately without waiting for ending of specified timestamp. (Click 1 -> New logic -> Click 2 -> New Logic -> Click 3 -> Old Logic and repeat every 3 seconds)
Can I do it with RxJava buffer? Otherwise what should I use in RxJava?
I've written code below and it's working fine, but my new logic executing only after waiting 3 seconds, can I make it execute immediately?
RxView.clicks(textField)
.observeOn(AndroidSchedulers.mainThread())
.buffer(3, TimeUnit.SECONDS, 3)
.filter(click -> (click.size() >= 1 && click.size() <= 3))
.subscribe(this::someFunc,
Throwable::printStackTrace);
private void someFunc(#NonNull List<Unit> list) {
if (list.size() == 3) {
Log.d("TAG", "if");
} else if (list.size() >= 1 && list.size() < 3) {
Log.d("TAG", "else if");
}
}
I want to achieve a logic like clicking on build number in android settings to become a developer, but in my case on 3 clicks should show "you are upgraded" message, on 1 click "press 2 more times", on 2 clicks "press 1 more time".

Related

Kotlin shuffle a list and validate list value with user value

I have a list that holds string values as directions, for each time is started is shuffle the list
val directions = mutableListOf("left","right","up","down")
directions.shuffle()
I am running a continuous loop to check if the percentage value has grown to a certain point before breaking the loop
if(progress != 100){
//continue until progress is 100
}
I send the instructions to the user and if they match the progress value increases
when(directions){
"left" -> {
// print direction to the user then check if followed
if(checkLeftDirection() == "left"){
// increment progress then remove left from the list
directions.remove("left")
progress +=10
}
// other directions
else -> {
//the loop always ends here
}
}
I want to send a list of random directions to the user and for each check if the user was correct and if the user is correct for a given direction then remove that direction from the list and send another random direction to the user.
what happens is the loop runs and does nothing and just goes to the else statement, it loops all directions then ends at the else statement,
UPDATE
here is the loop
if (progress != 100) {
for (item in directions) {
when(item){
"left" -> {
// print direction to the user then check if followed
if(checkLeftDirection() == item){
// increment progress then remove left from the list
directions.remove(item)
progress +=10
}
// other directions
else -> {
//the loop always ends here
}
}
}

Android - MutableSharedFlow failed to collect new values with multi subscribers

I want to create a shared view model for communication between MainActivity to fragments.
I decided to use share flow for managing events.
private val _sharedChannel: MutableSharedFlow<SharedEvent> = MutableSharedFlow(
replay = 0,extraBufferCapacity=0,onBufferOverflow = BufferOverflow.SUSPEND)
val sharedChannel = _sharedChannel.asSharedFlow()
I don't need to cache the last event, not even when orientation changes.. so I set "replay = 0"
When I collect the events only in my main activity - everything works fine:
lifecycleScope.launchWhenStarted {
gamePlaySharedViewModel.sharedChannel.collect { event->
SnappLog.log("GamePlayContainer-> sharedChannel EVENT: $event ")
when(event){
GamePlaySharedViewModel.SharedEvent.OnBackPress -> {
onBackPressed()
}
is GamePlaySharedViewModel.SharedEvent.BlockScreen -> {
blockScreen(event.isBlocked)
}
else -> {
}
}
}
}
}
When adding a second subscriber to another fragment - both of the subscribers stop receiving events after the first one (the first event send successfully.. )
what can I do to subscribe for multi MutableSharedFlow?
I've tried to increase the number of "replay" and to change the "onBufferOverflow" - nothing seems to work..

How to enable/disable to notification/indication in RxAndroidBLE

I am creating a RxJava2 chain where in I want to enable and disable notification. the flow I am setting is as follows.
establish a connection.
set the notification to READ_STATUS UUID.
if the returned byte is zero then perform a write byte 01 to WRITE_STATUS UUID and after WRITE_STATUS, enable the notification of READ_STATUS UUID to verify it has byte value 1.
else if the returned byte is 1 then just enable other indicators (UUID1, UUID2,UUD3) and read the value.
I have a problem at step 2 and 3 where I am reading the value of READ_STATUS UUID by enabling the notification. in order to re-read the value, I probably need to disable the notification and then again enable it. And to disable to the notification I have to dispose that particular setupNotification .
Code is as follows
connectDisposable=
device.establishConnection(false)
.flatMap(rxBleConnection -> {
rxBleConnection.discoverServices();
mRxBleConnection = rxBleConnection;
return Observable.just(rxBleConnection);
})
.flatMap(rxBleConnection ->mRxBleConnection.setupNotification(READ_STATUS,NotificationSetupMode.QUICK_SETUP).flatMap(it->it))
.takeUntil(bytes -> {
if(getByteValue(bytes)==0)
return false;// dispose above to disable the notification
else
return true; // no need to disable the notification and continue writing
})
.flatMap(bytes -> {
return Observable.zip(
mRxBleConnection.writeCharacteristic(WRITE_STATUS, new byte[]{1}).toObservable(),
// setupNotification again to check whether read status has 1 or not
mRxBleConnection.setupNotification(READ_STATUS, NotificationSetupMode.QUICK_SETUP).flatMap(it->it),
Pair::new
);
})
.flatMap(bytes ->{
byte [] val= bytes.first;
if(getByteValue(val) == 1){
return Observable.zip(
mRxBleConnection.setupIndication(HISTORY, NotificationSetupMode.QUICK_SETUP).doOnNext(observable -> Log.e(TAG,"Here 1 ")).flatMap(it -> it),
mRxBleConnection.setupIndication(PARAMCHECK, NotificationSetupMode.QUICK_SETUP).doOnNext(observable -> Log.e(TAG,"Here 2 ")).flatMap(it -> it),
mRxBleConnection.setupIndication(FAULTINFO, NotificationSetupMode.QUICK_SETUP).doOnNext(observable -> Log.e(TAG,"Here 3 ")).flatMap(it -> it),
Data::Readings);
}
return Observable.empty();
}).subscribe(data -> {
});
The problem with this code is my takeUntil is firing at the last it does not dispose the previous setupNotificaion operation so that I can re read it later.
I tried solution mentioned over this thread but unfortunately I am not sharing the RxBleConnection
The problem with this code is my takeUntil is firing at the last it does not dispose the previous setupNotificaion operation so that I can re read it later.
The problem is that your condition is inverted. From .takeUntil() Javadoc:
* #return an Observable that first emits items emitted by the source Observable, checks the specified
* condition after each item, and then completes when the condition is satisfied.
You have used:
.takeUntil(bytes -> {
if(getByteValue(bytes)==0)
return false;// dispose above to disable the notification
else
return true; // no need to disable the notification and continue writing
})
where it should be satisfied (return true) when the upstream should get disposed:
.takeUntil(bytes -> {
if(getByteValue(bytes)==0)
return true;// dispose above to disable the notification
else
return false; // no need to disable the notification and continue writing
})
To unsubscribe or to dispose setupNotification or setupIndication one can use the following code. I am sure there could be different ways but so far I could find this
private Observable<Pair<byte[],byte[]>> getValueFromIndication(RxBleConnection rxBleConnection){
final PublishSubject<Boolean> unsubscribeOperation= PublishSubject.create();
return Observable.zip(
rxBleConnection.setupIndication(TSDictionary.FAULT_RETRY_COUNT_SEQUENCE,NotificationSetupMode.QUICK_SETUP).flatMap(it->it).takeUntil(unsubscribeOperation),
rxBleConnection.setupIndication(TSDictionary.FAULT_RETRY_INFORMATION,NotificationSetupMode.QUICK_SETUP).flatMap(it->it).takeUntil(unsubscribeOperation),
(bytes, bytes2) -> {
unsubscribeOperation.onNext(true);
return Pair.create(bytes,bytes2);
}
);
}
In above code, I am zipping two indication operations and once I get the value from it I am unsubscribing from the change chain using PublishSubject and takeUntil.

Custom dialler, how can I send "1" or "2" via the call. For when you call a customer service and they need input

So I have this code, that takes my current call and plays the DTMF tone:
if (CallManager.currentCall != null) {
when (pressed) {
10 -> CallManager.currentCall?.playDtmfTone("*".toCharArray()[0])
11 -> CallManager.currentCall?.playDtmfTone("#".toCharArray()[0])
else -> CallManager.currentCall?.playDtmfTone(pressed!!.toChar())
}
}
But I make a call, for example to a big firm. and the machine enters.
"For sales press 1, for accounting press 2" and so on
I press on my view for the layout, and the code gets called, the current call exists, but even so, the call does not take my input. It doesn't respond to what I pressed.
What am I doing wrong?
I tried multiple default dialers and found that Drupe: https://play.google.com/store/apps/details?id=mobi.drupe.app&gl=NL
Can send the DTMF tones, so I assume this is possible.
This fixed it:
fun pressed(pressed: Int?) {
if (SIPManager.instance != null && SIPManager.instance?.numberOfActiveCalls ?: 0 > 0) {
SIPManager.instance!!.sendDTMF(null, pressed)
}
if (CallManager.currentCall != null) {
when (pressed) {
10 -> playDTMF("*".toCharArray()[0])
11 -> playDTMF("#".toCharArray()[0])
else -> playDTMF(pressed!!.toString().toCharArray()[0])
}
}
}
fun playDTMF(value: Char) {
Log.i("DTMF", "DTMF char is: " + value)
CallManager.currentCall!!.playDtmfTone(value)
Handler().postDelayed({
CallManager.currentCall!!.stopDtmfTone()
}, 250)
}
Was sending wrong chars

How to manage parallel and serial Retrofit API calls

I have 4 API calls in the same activity. 3 of them are independent of each other.I would like to call number 4 after first three finished and I am not sure the execution of first 3 in every time. I get data from database then it will call. It may 1 API call or 2 or 3 among first three.
I tried to call one after another sequentially but sometimes number 4 starts before first 3 finished. some of my efforts given below:
if(true){ // data 1 is available in database
firstRetrofitCall();
}else{
//show no data
}
if(true){ // data 2 is available in database
secondRetrofitCall();
}else{
//show no data
}
if(true){ // data 3 is available in database
thirdRetrofitCall();
}else{
//show no data
}
fourthRetrofitCall(); // I would like to execute this after first three finished
is it possible to manage using RxJava?
Use Rxjava2 adapter with Retrofit and then you can use Rxjava's zip operator to combine first three calls like this(assuming your calls return X,Y,Z values respectively and XYZwrapper is just container for these) and then flatMap operator to do the fourth call.
Single.zip(
firstRetrofitCall(),
secondRetrofitCall(),
thirdRetrofitCall(),
Function3<X, Y, Z, XYZwrapper> { x, y, z -> return#Function3 XYZwrapper(x, y, z) }
)
.subscribeOn(Schedulers.io())
.flatMap { XYZwrapper -> fourthRetrofitCall().subscribe() }//chaining
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy( onError = {}, onSuccess = {})
Declare a Boolean array of size 3 and initialize its indexes to false. Update the index to true in each 1st three API call's onResponse method. For example set index 0 to true for API call 1 and so on. And check in onResponse method that each of the array indexes are true if true then call the fourth API.
Add a boolean flag for each of those calls
boolean isFirstExecuted;
boolean isSecondExecuted;
boolean isThirdExecuted;
if(true){ // data 1 is available in database
firstRetrofitCall();
}else{
isFirstExecuted = true;
}
if(true){ // data 2 is available in database
secondRetrofitCall();
}else{
isSecondExecuted = true;
}
if(true){ // data 3 is available in database
thirdRetrofitCall();
}else{
isThirdExecuted = true;
}
checkAndExceuteFourth();
onFirstResponse(){
isFirstExecuted = true;
checkAndExceuteFourth();
}
onSecondResponse(){
isSecondExecuted = true;
checkAndExceuteFourth();
}
onThirdResponse(){
isThirdExecuted = true;
checkAndExceuteFourth();
}
Method for checking and executing fourth
public void checkAndExceuteFourth(){
if(isFirstExecuted && isFirstExecuted && isFirstExecuted ){
fourthRetrofitCall();
}
}

Categories

Resources