androidalarmmanagerandroid-vibrationmoto-360ambient

Frequent Wearable Vibrations with Ambient/Blackscreen


I'm trying to write an App for a Smartwatch that simulates your heartbeat, so it needs to be able to vibrate in time intervals of 1s to about 0.5-0.3s, for a duration of 75ms.

It also needs to do this, when the App enters ambient mode or starts to go full blackscreen. I don't care about power consumption or whatever, it should just be able to run for like 20-30minutes, nothing else.

On the Moto360 on which I'm developing, the ambient mode will turn into a full blackscreen, if you do not keep the watch in a certain position, and as soon as it enters blackscreen, the vibration will stop, so I need a solution that will also work for the blackscreen, unless there is a way to stop the watch, going into blackscreen, which I do not know of.

When just working with onEnterAmbient etc. events, the watch stops vibrating, when you don't hold it in the right angle due to going into blackscreen, and also the vibration is not always consistent, because of having to call the vibrator.vibrate() method again upon entering/updating, etc, so it usually leads to small inconsistency in the vibration pattern, which should be avoided. So the approach of using the ambientmode does not work I think.

Here is the former Code:

[...]
private long[] vibrationPattern_StandardPulse = {0, 75, 1000};
private long[] vibrationPattern_AcceleratedPulse = {0, 75, 600};
[...]
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setAmbientEnabled();
    mContainerView = (BoxInsetLayout) findViewById(R.id.container);
    vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
[...]
@Override
public void onEnterAmbient(Bundle ambientDetails) {
    super.onEnterAmbient(ambientDetails);
    keepVibrating();
}

@Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();
    keepVibrating();
}

@Override
public void onExitAmbient() {
    super.onExitAmbient();
    keepVibrating();
[...]
 public void keepVibrating() {
    if (standardPulse) {
        vibrator.vibrate(vibrationPattern_StandardPulse, 0);
    } else {
        vibrator.vibrate(vibrationPattern_AcceleratedPulse, 0);
    }
}
[...]

So I tried it again with the alarmmanager, (sticking to this link: https://developer.android.com/training/wearables/apps/always-on.html#UpdateContent) to be able to also send vibrations when in Blackscreen but as it turns out, the timer for the alarmmanager can not be set to such small intervals? It only vibrates every about 5s, as supposed to 1s and less regardless of being in black screen, or normal or ambient mode...

Code:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setAmbientEnabled();
    mAmbientStateAlarmManager =
            (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent ambientStateIntent =
            new Intent(getApplicationContext(), MainActivity.class);

    mAmbientStatePendingIntent = PendingIntent.getActivity(
            getApplicationContext(),
            0,
            ambientStateIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    mContainerView = (BoxInsetLayout) findViewById(R.id.container);
    //mClockView = (TextView) findViewById(R.id.clock);
    vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
[...]}
@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    setIntent(intent);

    refreshDisplayAndSetNextUpdate();
}

private long AMBIENT_INTERVAL_MS = 0;

private void refreshDisplayAndSetNextUpdate() {
    if (standardPulse) {
        AMBIENT_INTERVAL_MS = 1000;
    } else {
        AMBIENT_INTERVAL_MS = 600;
    }

    if (isAmbient()) {
        // Implement data retrieval and update the screen for ambient mode
        vibrator.vibrate(75);
    } else {
        // Implement data retrieval and update the screen for interactive mode
        vibrator.vibrate(75);
    }

    long timeMs = System.currentTimeMillis();

    // Schedule a new alarm
    if (isAmbient()) {
        // Calculate the next trigger time
        long triggerTimeMs = timeMs + AMBIENT_INTERVAL_MS;

        mAmbientStateAlarmManager.setExact(
                AlarmManager.RTC_WAKEUP,
                triggerTimeMs,
                mAmbientStatePendingIntent);

    } else {
        // Calculate the next trigger time for interactive mode
        long triggerTimeMs = timeMs + AMBIENT_INTERVAL_MS;

        mAmbientStateAlarmManager.setExact(
                AlarmManager.RTC_WAKEUP,
                triggerTimeMs,
                mAmbientStatePendingIntent);
    }
}

RefreshUpdateAndSetNextAlarm is then called also in the onEnterAmbient events etc. but not working as it is supposed to. Is there a way to do such things on a smartwatch, particularly on the Moto 360?

Maybe if I send messages constantly from the smartphone via the messageAPI and set them to urgent?


Solution

  • Solution was to use CPU Wakelock:

    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "MyWakelockTag");
    wakeLock.acquire();
    

    and screen keep on-Flag:

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);