javaandroidwear-osandroid-wear-2.0wear-os-tiles

How do Wear OS Tiles update themselve every second?


I have made a tile that should show the current heart rate. The tile gets the heart rate from shared preferences and it works perfectly but I need to refresh it like every second. Currently, I can only refresh it every minute using .setFreshnessIntervalMillis(1000*60)

The documentation says that I can update my tile from any place in my application using this...

TileService.getUpdater(context)
       .requestUpdate(HeartRateTileService.class);

But this does nothing. I tried it in several locations like in onItemSelected inside my MainActivity, inside a BroadcastReceiver and inside a foreground service. Is this a context problem or something? I also tried

HeartRateTileService.getUpdater(this/getApplicationContext())
       .requestUpdate(HeartRateTileService.class);

This is my tile...

public class HeartRateTileService extends TileService {
    private static final String RESOURCES_VERSION = "1";

    private String currentHeartrate = "0";
    private PrefManager prefManager;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int i = super.onStartCommand(intent, flags, startId);

        Log.d("HeartRate", "onStartCommand " + prefManager.getHeartrate());

        return i;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        prefManager = new PrefManager(this);
        Log.d("HeartRate", "onCreate " + prefManager.getHeartrate());
    }

    @NonNull
    @Override
    protected ListenableFuture<TileBuilders.Tile> onTileRequest(
            @NonNull RequestBuilders.TileRequest requestParams
    ) {
        Log.d("HeartRate", "onTileRequest " + prefManager.getHeartrate());
        return Futures.immediateFuture(new TileBuilders.Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setFreshnessIntervalMillis(1000*60)
                .setTimeline(new TimelineBuilders.Timeline.Builder()
                        .addTimelineEntry(new TimelineBuilders.TimelineEntry.Builder()
                                .setLayout(new LayoutElementBuilders.Layout.Builder()
                                        .setRoot(
                                                layoutHeartRate()
                                        ).build()
                                ).build()
                        ).build()
                ).build()
        );
    }

    private LayoutElementBuilders.LayoutElement layoutPlay() {
        return new LayoutElementBuilders.Box.Builder()
                .setWidth(wrap())
                .setHeight(expand())
                .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_CENTER)
                .addContent(new LayoutElementBuilders.Row.Builder()
                        .addContent(
                                IconButton.buildIconButton(
                                        this,
                                        "ic_play",
                                        R.color.colorAccent,
                                        "start measuring heart rate",
                                        new ModifiersBuilders.Clickable.Builder()
                                                .setOnClick(new ActionBuilders.LaunchAction.Builder()
                                                        .setAndroidActivity(new ActionBuilders.AndroidActivity.Builder()
                                                                .setClassName(MainActivity.class.getName())
                                                                .setPackageName(this.getPackageName())
                                                                .build()
                                                        ).build()
                                                )
                                                .build()
                                )
                        ).build()
                )
                .build();
    }

    private LayoutElementBuilders.LayoutElement layoutHeartRate() {
        prefManager = new PrefManager(this);
        currentHeartrate = prefManager.getHeartrate();
        return new LayoutElementBuilders.Box.Builder()
                .setWidth(wrap())
                .setHeight(expand())
                .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_CENTER)
                .addContent(new LayoutElementBuilders.Row.Builder()
                        .addContent(
                                IconButton.buildIconButton(
                                        this,
                                        "",
                                        R.color.colorAccent,
                                        "start measuring heart rate",
                                        new ModifiersBuilders.Clickable.Builder()
                                                .setOnClick(new ActionBuilders.LaunchAction.Builder()
                                                        .setAndroidActivity(new ActionBuilders.AndroidActivity.Builder()
                                                                .setClassName(MainActivity.class.getName())
                                                                .setPackageName(this.getPackageName())
                                                                .build()
                                                        ).build()
                                                )
                                                .build()
                                )
                        ).build()
                )
                .addContent(new LayoutElementBuilders.Text.Builder()
                        .setText(prefManager.getHeartrate())
                        .build()
                )
                .build();
    }

    @NonNull
    @Override
    protected ListenableFuture<ResourceBuilders.Resources> onResourcesRequest(
            @NonNull RequestBuilders.ResourcesRequest requestParams
    ) {
        Log.d("HeartRate", "onResourcesRequest " + prefManager.getHeartrate());
        return Futures.immediateFuture(new ResourceBuilders.Resources.Builder()
                .setVersion(RESOURCES_VERSION)
                .addIdToImageMapping("ic_play", new ResourceBuilders.ImageResource.Builder()
                        .setAndroidResourceByResId(new ResourceBuilders.AndroidImageResourceByResId.Builder()
                                .setResourceId(R.drawable.ic_play)
                                .build()
                        ).build()
                )
                .build()
        );
    }

}

Solution

  • There is a minimum time of 20 seconds.

    See https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/manager/UpdateScheduler.java;l=31?q=20%20f:androidx%2Fwear%2Ftiles&start=51

        @VisibleForTesting static final long MIN_INTER_UPDATE_INTERVAL_MILLIS = SECONDS.toMillis(20);