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