Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.os.Parcel;
     22 import android.os.SystemClock;
     23 
     24 import java.util.Objects;
     25 
     26 /**
     27  * A value with an associated reference time. The reference time will typically be provided by the
     28  * elapsed realtime clock. The elapsed realtime clock can be obtained using methods like
     29  * {@link SystemClock#elapsedRealtime()} or {@link SystemClock#elapsedRealtimeClock()}.
     30  * If a suitable clock is used the reference time can be used to identify the age of a value or
     31  * ordering between values.
     32  *
     33  * <p>To read and write a timestamped value from / to a Parcel see
     34  * {@link #readFromParcel(Parcel, ClassLoader, Class)} and
     35  * {@link #writeToParcel(Parcel, TimestampedValue)}.
     36  *
     37  * @param <T> the type of the value with an associated timestamp
     38  * @hide
     39  */
     40 public final class TimestampedValue<T> {
     41     private final long mReferenceTimeMillis;
     42     private final T mValue;
     43 
     44     public TimestampedValue(long referenceTimeMillis, T value) {
     45         mReferenceTimeMillis = referenceTimeMillis;
     46         mValue = value;
     47     }
     48 
     49     public long getReferenceTimeMillis() {
     50         return mReferenceTimeMillis;
     51     }
     52 
     53     public T getValue() {
     54         return mValue;
     55     }
     56 
     57     @Override
     58     public boolean equals(Object o) {
     59         if (this == o) {
     60             return true;
     61         }
     62         if (o == null || getClass() != o.getClass()) {
     63             return false;
     64         }
     65         TimestampedValue<?> that = (TimestampedValue<?>) o;
     66         return mReferenceTimeMillis == that.mReferenceTimeMillis
     67                 && Objects.equals(mValue, that.mValue);
     68     }
     69 
     70     @Override
     71     public int hashCode() {
     72         return Objects.hash(mReferenceTimeMillis, mValue);
     73     }
     74 
     75     @Override
     76     public String toString() {
     77         return "TimestampedValue{"
     78                 + "mReferenceTimeMillis=" + mReferenceTimeMillis
     79                 + ", mValue=" + mValue
     80                 + '}';
     81     }
     82 
     83     /**
     84      * Read a {@link TimestampedValue} from a parcel that was stored using
     85      * {@link #writeToParcel(Parcel, TimestampedValue)}.
     86      *
     87      * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
     88      * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
     89      * supported by those methods.
     90      *
     91      * @param in the Parcel to read from
     92      * @param classLoader the ClassLoader to pass to {@link Parcel#readValue(ClassLoader)}
     93      * @param valueClass the expected type of the value, typically the same as {@code <T>} but can
     94      *     also be a subclass
     95      * @throws RuntimeException if the value read is not compatible with {@code valueClass} or the
     96      *     object could not be read
     97      */
     98     @SuppressWarnings("unchecked")
     99     @NonNull
    100     public static <T> TimestampedValue<T> readFromParcel(
    101             @NonNull Parcel in, @Nullable ClassLoader classLoader, Class<? extends T> valueClass) {
    102         long referenceTimeMillis = in.readLong();
    103         T value = (T) in.readValue(classLoader);
    104         // Equivalent to static code: if (!(value.getClass() instanceof {valueClass})) {
    105         if (value != null && !valueClass.isAssignableFrom(value.getClass())) {
    106             throw new RuntimeException("Value was of type " + value.getClass()
    107                     + " is not assignable to " + valueClass);
    108         }
    109         return new TimestampedValue<>(referenceTimeMillis, value);
    110     }
    111 
    112     /**
    113      * Write a {@link TimestampedValue} to a parcel so that it can be read using
    114      * {@link #readFromParcel(Parcel, ClassLoader, Class)}.
    115      *
    116      * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
    117      * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
    118      * supported by those methods.
    119      *
    120      * @param dest the Parcel
    121      * @param timestampedValue the value
    122      * @throws RuntimeException if the value could not be written to the Parcel
    123      */
    124     public static void writeToParcel(
    125             @NonNull Parcel dest, @NonNull TimestampedValue<?> timestampedValue) {
    126         dest.writeLong(timestampedValue.mReferenceTimeMillis);
    127         dest.writeValue(timestampedValue.mValue);
    128     }
    129 
    130     /**
    131      * Returns the difference in milliseconds between two instance's reference times.
    132      */
    133     public static long referenceTimeDifference(
    134             @NonNull TimestampedValue<?> one, @NonNull TimestampedValue<?> two) {
    135         return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
    136     }
    137 }
    138