Search code examples
android-studioalarmmanagerwear-oswatch-face-api

Code example for android-wear watch using AlarmManager to update in ambient mode?


I'm looking for an example of code for an android watch that uses the AlarmManager class to update the face in ambient mode.

Please provide a link or past the code.

Thank you.


Solution

  • I have developed an Android watch face that also needed to run a method periodically (e.g. every hour). At first a handler seemed to be a good solution, but it stops working when the Android Wear device goes to sleep. Then, I came across the article Keeping Your App Visible and the section "Update Content in Ambient Mode". However, it is not that easy to understand how it applies to watch faces. The solution described here is enabling a periodic update on the watch face, even when the Android Wear device goes to sleep.

    Start by adding the following fields to your watch face:

    /**
     * Action for the update in ambient mode, per our custom refresh cycle.
     */
    private static final String UPDATE_ACTION = "your.package.action.UPDATE";
    /**
     * Milliseconds between waking processor/screen for updates
     */
    private static final long UPDATE_RATE = TimeUnit.MINUTES.toMillis(30);
    private AlarmManager mUpdateAlarmManager;
    private PendingIntent mUpdatePendingIntent;
    private BroadcastReceiver mUpdateBroadcastReceiver;
    

    In this example, the update is done every 30 minutes. In order to preserve battery power, most wear apps should not frequently update the screen while in ambient mode. Frequent updates have a significant impact on the battery power.

    This is what the onCreateEngine() method looks like on my watch face:

    @Override
    public Engine onCreateEngine() {
    
        /* Set an AlarmManager. The AlarmManager calls itself again in the end for a periodic update. */
        mUpdateAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    
        Intent ambientUpdateIntent = new Intent(UPDATE_ACTION);
    
        mUpdatePendingIntent = PendingIntent.getBroadcast(
                getApplicationContext(), 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
        mUpdateBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(this.getClass().getName(), "Broadcast received!");
                doMyUpdateAndScheduleNewUpdate();
            }
        };
        IntentFilter filter = new IntentFilter(UPDATE_ACTION);
        registerReceiver(mUpdateBroadcastReceiver, filter);
    
        doMyUpdateAndScheduleNewUpdate();
    
        return new Engine();
    }
    

    doMyUpdateAndScheduleNewUpdate() is the method that executes whatever you want to do periodically. Inside that method call also scheduleNewAlarm() - this is very important, as it is the method that will schedule your following alarm. It should be something like:

    /**
     * Schedule the next alarm that will call onReceive of the BroadcastReceiver.
     */
    private void scheduleNewAlarm() {
        // Calculate the next trigger time
        long triggerTimeMs = System.currentTimeMillis() + UPDATE_RATE;
        mUpdateAlarmManager.setExact(
                AlarmManager.RTC_WAKEUP,
                triggerTimeMs,
                mUpdatePendingIntent);
    }
    

    Finally, override the onDestroy method of your WatchFaceService, which is called right before the service is going away. There, we want to cancel the update Intent and unregister the broadcast receiver. Basically, add this code:

    @Override
    public void onDestroy() {
        // take care of the AlarmManager periodic update
        mUpdateAlarmManager.cancel(mUpdatePendingIntent);
        unregisterReceiver(mUpdateBroadcastReceiver);
        super.onDestroy();
    }