public class

PlatformTimeUpdateNotifierImpl

extends java.lang.Object

implements PlatformTimeUpdateNotifier

 java.lang.Object

↳androidx.wear.protolayout.expression.pipeline.PlatformTimeUpdateNotifierImpl

Gradle dependencies

compile group: 'androidx.wear.protolayout', name: 'protolayout-expression-pipeline', version: '1.2.0'

  • groupId: androidx.wear.protolayout
  • artifactId: protolayout-expression-pipeline
  • version: 1.2.0

Artifact androidx.wear.protolayout:protolayout-expression-pipeline:1.2.0 it located at Google repository (https://maven.google.com/)

Overview

Controls notifying for time-related updates using Android's clock. Updates can also be enabled/disabled.

Summary

Constructors
publicPlatformTimeUpdateNotifierImpl()

Methods
public voidclearReceiver()

public voidsetReceiver(java.util.concurrent.Executor executor, java.lang.Runnable tick)

Sets the callback to be called whenever platform time needs to be reevaluated.

public voidsetUpdatesEnabled(boolean updatesEnabled)

Sets whether this notifier can send updates on the given receiver.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public PlatformTimeUpdateNotifierImpl()

Methods

public void setReceiver(java.util.concurrent.Executor executor, java.lang.Runnable tick)

Sets the callback to be called whenever platform time needs to be reevaluated. Note that this doesn't call the callback immediately.

public void clearReceiver()

public void setUpdatesEnabled(boolean updatesEnabled)

Sets whether this notifier can send updates on the given receiver.

Source

/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.wear.protolayout.expression.pipeline;

import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;

import java.util.concurrent.Callable;
import java.util.concurrent.Executor;

/**
 * Controls notifying for time-related updates using Android's clock. Updates can also be
 * enabled/disabled.
 */
@RestrictTo(Scope.LIBRARY_GROUP)
public class PlatformTimeUpdateNotifierImpl implements PlatformTimeUpdateNotifier {
    private static final String TAG = "PlatformTimeUpdateNotifierImpl";
    private final Handler mUiHandler = new Handler(Looper.getMainLooper());
    @Nullable private Runnable mRegisteredReceiver;
    private final Runnable mNotifyAndSchedule = this::notifyAndScheduleNextSecond;
    private long mLastScheduleTimeMillis = 0;
    private boolean mUpdatesEnabled = true;
    @Nullable private Executor mRegisteredExecutor;

    /**
     * Sets the callback to be called whenever platform time needs to be reevaluated. Note that this
     * doesn't call the callback immediately.
     */
    @Override
    public void setReceiver(@NonNull Executor executor, @NonNull Runnable tick) {
        if (mRegisteredReceiver != null) {
            Log.w(TAG, "Clearing previously set receiver.");
            clearReceiver();
        }
        mRegisteredReceiver = tick;
        mRegisteredExecutor = executor;

        if (mUpdatesEnabled) {
            // Send first update and schedule next.
            mLastScheduleTimeMillis = SystemClock.uptimeMillis();
            scheduleNextSecond();
        }
    }

    @Override
    public void clearReceiver() {
        mRegisteredReceiver = null;
        mRegisteredExecutor = null;

        // There are no more registered callbacks, stop the periodic call.
        if (this.mUpdatesEnabled) {
            mUiHandler.removeCallbacks(this.mNotifyAndSchedule, this);
        }
    }

    /** Sets whether this notifier can send updates on the given receiver. */
    public void setUpdatesEnabled(boolean updatesEnabled) {
        if (updatesEnabled == this.mUpdatesEnabled) {
            return;
        }

        this.mUpdatesEnabled = updatesEnabled;

        if (!updatesEnabled) {
            mUiHandler.removeCallbacks(this.mNotifyAndSchedule, this);
        } else if (mRegisteredReceiver != null) {
            mLastScheduleTimeMillis = SystemClock.uptimeMillis();
            notifyAndScheduleNextSecond();
        }
    }


    @SuppressWarnings("ExecutorTaskName")
    private void notifyAndScheduleNextSecond() {
        if (!this.mUpdatesEnabled) {
            return;
        }

        if (mRegisteredReceiver != null) {
            runReceiver();
        }
        // Trigger updates.
        scheduleNextSecond();
    }

    /** Call {@link Callable#call()} on the registered receiver and handles exception. */
    private void runReceiver() {
        if (mRegisteredReceiver == null || mRegisteredExecutor == null) {
            return;
        }

        mRegisteredExecutor.execute(mRegisteredReceiver);
    }

    private void scheduleNextSecond() {
        // Set up for the next update.
        mLastScheduleTimeMillis += 1000;

        // Ensure that the new time is actually in the future. If a call from uiHandler gets
        // significantly delayed for any reason, then without this, we'll reschedule immediately
        // (potentially multiple times), compounding the situation further.
        if (mLastScheduleTimeMillis < SystemClock.uptimeMillis()) {
            // Skip the failed updates...
            long missedTime = SystemClock.uptimeMillis() - mLastScheduleTimeMillis;

            // Round up to the nearest second...
            missedTime = ((missedTime / 1000) + 1) * 1000;
            mLastScheduleTimeMillis += missedTime;
        }

        mUiHandler.postAtTime(this.mNotifyAndSchedule, this, mLastScheduleTimeMillis);
    }
}