Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 091071da authored by Stevie Kideckel's avatar Stevie Kideckel Committed by Automerger Merge Worker
Browse files

Merge "Performance/jank improvements to AnalogClock" into sc-dev am: 9a0e124b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14487521

Change-Id: I8e2a6da8980de7d71b9c79806dc58fa983188545
parents 0ee9ace4 9a0e124b
Loading
Loading
Loading
Loading
+45 −28
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.graphics.BlendMode;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Canvas;
@@ -40,8 +39,9 @@ import android.widget.RemoteViews.RemoteView;


import java.time.Clock;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneId;
import java.util.Formatter;
import java.util.Formatter;
import java.util.Locale;
import java.util.Locale;
@@ -61,8 +61,8 @@ import java.util.Locale;
@Deprecated
@Deprecated
public class AnalogClock extends View {
public class AnalogClock extends View {
    private static final String LOG_TAG = "AnalogClock";
    private static final String LOG_TAG = "AnalogClock";
    /** How often the clock should refresh to make the seconds hand advance at ~15 FPS. */
    /** How many times per second that the seconds hand advances. */
    private static final long SECONDS_TICK_FREQUENCY_MS = 1000 / 15;
    private static final long SECONDS_HAND_FPS = 30;


    private Clock mClock;
    private Clock mClock;
    @Nullable
    @Nullable
@@ -106,7 +106,6 @@ public class AnalogClock extends View {
    public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        super(context, attrs, defStyleAttr, defStyleRes);


        final Resources r = context.getResources();
        final TypedArray a = context.obtainStyledAttributes(
        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
                attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
@@ -716,25 +715,34 @@ public class AnalogClock extends View {
    }
    }


    private void onTimeChanged() {
    private void onTimeChanged() {
        long nowMillis = mClock.millis();
        Instant now = mClock.instant();
        LocalDateTime localDateTime = toLocalDateTime(nowMillis, mClock.getZone());
        onTimeChanged(now.atZone(mClock.getZone()).toLocalTime(), now.toEpochMilli());

    }
        int hour = localDateTime.getHour();

        int minute = localDateTime.getMinute();
    private void onTimeChanged(LocalTime localTime, long nowMillis) {
        int second = localDateTime.getSecond();
        float previousHour = mHour;

        float previousMinutes = mMinutes;
        mSeconds = second + localDateTime.getNano() / 1_000_000_000f;

        mMinutes = minute + second / 60.0f;
        float rawSeconds = localTime.getSecond() + localTime.getNano() / 1_000_000_000f;
        mHour = hour + mMinutes / 60.0f;
        // We round the fraction of the second so that the seconds hand always occupies the same
        // n positions between two given numbers, where n is the number of ticks per second. This
        // ensures the second hand advances by a consistent distance despite our handler callbacks
        // occurring at inconsistent frequencies.
        mSeconds = Math.round(rawSeconds * SECONDS_HAND_FPS) / (float) SECONDS_HAND_FPS;
        mMinutes = localTime.getMinute() + mSeconds / 60.0f;
        mHour = localTime.getHour() + mMinutes / 60.0f;
        mChanged = true;
        mChanged = true;


        // Update the content description only if the announced hours and minutes have changed.
        if ((int) previousHour != (int) mHour || (int) previousMinutes != (int) mMinutes) {
            updateContentDescription(nowMillis);
            updateContentDescription(nowMillis);
        }
        }
    }


    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        @Override
        public void onReceive(Context context, Intent intent) {
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
            if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
                createClock();
                createClock();
            }
            }


@@ -747,15 +755,32 @@ public class AnalogClock extends View {
    private final Runnable mSecondsTick = new Runnable() {
    private final Runnable mSecondsTick = new Runnable() {
        @Override
        @Override
        public void run() {
        public void run() {
            removeCallbacks(this);
            if (!mVisible || mSecondHand == null) {
            if (!mVisible || mSecondHand == null) {
                return;
                return;
            }
            }


            onTimeChanged();
            Instant now = mClock.instant();
            LocalTime localTime = now.atZone(mClock.getZone()).toLocalTime();
            // How many milliseconds through the second we currently are.
            long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis();
            // How many milliseconds there are between tick positions for the seconds hand.
            double millisPerTick = 1000 / (double) SECONDS_HAND_FPS;
            // How many milliseconds we are past the last tick position.
            long millisPastLastTick = Math.round(millisOfSecond % millisPerTick);
            // How many milliseconds there are until the next tick position.
            long millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick);
            // If we are exactly at the tick position, this could be 0 milliseconds due to rounding.
            // In this case, advance by the full amount of millis to the next position.
            if (millisUntilNextTick <= 0) {
                millisUntilNextTick = Math.round(millisPerTick);
            }
            // Schedule a callback for when the next tick should occur.
            postDelayed(this, millisUntilNextTick);


            invalidate();
            onTimeChanged(localTime, now.toEpochMilli());


            postDelayed(this, SECONDS_TICK_FREQUENCY_MS);
            invalidate();
        }
        }
    };
    };


@@ -782,14 +807,6 @@ public class AnalogClock extends View {
        setContentDescription(contentDescription);
        setContentDescription(contentDescription);
    }
    }


    private static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zoneId) {
        // java.time types like LocalDateTime / Instant can support the full range of "long millis"
        // with room to spare so we do not need to worry about overflow / underflow and the
        // resulting exceptions while the input to this class is a long.
        Instant instant = Instant.ofEpochMilli(timeMillis);
        return LocalDateTime.ofInstant(instant, zoneId);
    }

    /**
    /**
     * Tries to parse a {@link ZoneId} from {@code timeZone}, returning null if it is null or there
     * Tries to parse a {@link ZoneId} from {@code timeZone}, returning null if it is null or there
     * is an error parsing.
     * is an error parsing.