0

I'm writing a WearOS app that tries to tell the time by vibrating. (e.g. if the time is 4:12 it will vibrate 4 times, then 1 time, then 2 times) I doubt this has much practical use, but I'm doing it as a way to learn about android app development.

I'm trying to use handler.postDelayed for the delay between the vibrations, but this only works once. After it successfully triggers the handler once, I need to restart the activity for it to work again. Why?

My relevant code is here:

    int[] pulses = new int[4]; //length 4, one for each possible digit of the time

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //some init code goes here
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);

        pulses[0] = hour/10;
        pulses[1] = hour%10;
        pulses[2] = minute/10;
        pulses[3] = minute%10;

        RelativeLayout parent_layout = findViewById(R.id.parent_layout);
        parent_layout.setOnTouchListener(new TotalGestureDetector(this){
            @Override
            public void onDoubleTap(MotionEvent e) {
                Toast.makeText(getApplicationContext(), "Double-Tap", Toast.LENGTH_SHORT).show();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        int time = vibratePattern();
                        if (time < 0){
                            return; //no need to re-call the function
                        }
                        new Handler().postDelayed(this, time);
                        return;
                    }
                }, 500);

            }
        });

    private int vibratePattern(){
        int pulse_len = 130;
        int pause_len = 100;
        int delay_between_digits = 1250;
        for(int i = 0; i < pulses.length; i++){
            if (pulses[i] > 0){
                pulses[i]--;
                buzz(pulse_len);
                return pulse_len + pause_len;
            } else if( pulses[i] == 0){
                //don't vibrate, insert delay between digits
                pulses[i]--; //set this to -1 so we know it is acted upon
                return delay_between_digits;
            } else {
                //Do nothing, let the loop continue to the next digit in the time.
            }
        }
        //if it ever gets here, array is empty
        //return -1 to show that no more calls are needed
        return -1;
    }

Sorry if that's a lot of code.

buzz is just a function I have that vibrates the device for the amount of ms it is given

TotalGestureDetector is a class which I just yoinked from here: https://gist.github.com/nesquena/b2f023bb04190b2653c7 and renamed.

parent_layout is literally just the default layout in an empty activity -- screen is blank I want this app to be vibration-only.

Oren
  • 84
  • 10
  • (e.g. if the time is 4:12 it will vibrate 4 times, then 1 time, then 2 times) your solution work 7 times in case, and it doen't happen again right? – Công Hải May 20 '20 at 01:50

1 Answers1

2

You should revert value of pulses again when it already vibrate all. Try this

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        int time = vibratePattern();
        if (time < 0){
            pulses[0] = hour/10;
            pulses[1] = hour%10;
            pulses[2] = minute/10;
            pulses[3] = minute%10;
            return; //no need to re-call the function
        }
        new Handler().postDelayed(this, time);
        return;
    }
}, 500);
Rahul Gaur
  • 1,661
  • 1
  • 13
  • 29
Công Hải
  • 4,961
  • 3
  • 14
  • 20
  • Ahhhh Red herring. I was worried about why postDelayed wasn't working, and didn't consider that my function was mutating the list and then didn't have anything to do when it was called the next time. – Oren May 20 '20 at 01:59
  • 1
    Should make Handle() global variable instead of new object inside Runnable :) – Công Hải May 20 '20 at 02:01