Solution for the Magic Sequence Problem with RxJava

Problem

Given that we have two buttons, A and B, we want to print a message if a “secret combination” (ABBABA)
is clicked within 5 seconds, here are the requirements :

  • Print the message immediately when the secret combination is clicked.
  • Don't wait until the end of the 5 second interval before the message is printed.
  • As soon as the secret combination is entered (within 5 seconds) display the message. For example a combination like “BBABBABA” is ok as long as “ABBABA” is clicked within 5 seconds.

Solution

 private static final String MAGIC_SEQUENCE = "ABBABA";
 Observable obsButtonA = RxView.clicks(buttonA).map(new  
    Func1<Void, String>() {
      @Override public String call(Void aVoid) {
        return "A";
      }
    });
    Observable obsButtonB = RxView.clicks(buttonB).map(new 
      Func1<Void, String>() {
      @Override public String call(Void aVoid) {
        return "B";
      }
    });

    Observable obsButtons = Observable.merge(obsButtonA, 
     obsButtonB);
    obsButtons.buffer(MAGIC_SEQUENCE.length(), 1)
        .timeout(5000, TimeUnit.SECONDS, 
          Observable.just(new ArrayList<String>()))
        .repeat() 
        .doOnNext(new Action1<List<String>>() {
          @Override public void call(List<String> strings) {
            resultView.setText(concatStringsWSep(strings, 
            ""));
          }
        })
        .filter(new Func1<List<String>, Boolean>() {
          @Override public Boolean call(List<String> strings) {
            return concatStringsWSep(strings, 
            "").equals(MAGIC_SEQUENCE);
          }
        })
        .subscribe(new Action1<List<String>>() {
          @Override public void call(List<String> strings) {
            resultView.setText("BRAVO! Magic Sequence entered.");
          }
        }); 

buffer just emits an array containing with the last 6 characters, which is what we want.
the paramter 1 for skip in buffer makes the next buffer start with the previous buffer's start point + 1 so we start with the next values after the 6 characters.

And we are using repeat here because When and if the timeout operation emits the empty array (no input after 5000), the Observable is completed), so we need to resubscribe to the above chain so that next input will still be
handled.

Here's the final solution on Github