content: /*
   * Copyright (C) 2018 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 android.util;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.os.Parcel;
  import android.os.SystemClock;
  
  import java.util.Objects;
  
  /**
   * A value with an associated reference time. The reference time will typically be provided by the
   * elapsed realtime clock. The elapsed realtime clock can be obtained using methods like
   * {@link SystemClock#elapsedRealtime()} or {@link SystemClock#elapsedRealtimeClock()}.
   * If a suitable clock is used the reference time can be used to identify the age of a value or
   * ordering between values.
   *
   * <p>To read and write a timestamped value from / to a Parcel see
   * {@link #readFromParcel(Parcel, ClassLoader, Class)} and
   * {@link #writeToParcel(Parcel, TimestampedValue)}.
   *
   * @param <T> the type of the value with an associated timestamp
   * @hide
   */
  public final class TimestampedValue<T> {
      private final long mReferenceTimeMillis;
      private final T mValue;
  
      public TimestampedValue(long referenceTimeMillis, T value) {
          mReferenceTimeMillis = referenceTimeMillis;
          mValue = value;
      }
  
      public long getReferenceTimeMillis() {
          return mReferenceTimeMillis;
      }
  
      public T getValue() {
          return mValue;
      }
  
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
          if (o == null || getClass() != o.getClass()) {
              return false;
          }
          TimestampedValue<?> that = (TimestampedValue<?>) o;
          return mReferenceTimeMillis == that.mReferenceTimeMillis
                  && Objects.equals(mValue, that.mValue);
      }
  
      @Override
      public int hashCode() {
          return Objects.hash(mReferenceTimeMillis, mValue);
      }
  
      @Override
      public String toString() {
          return "TimestampedValue{"
                  + "mReferenceTimeMillis=" + mReferenceTimeMillis
                  + ", mValue=" + mValue
                  + '}';
      }
  
      /**
       * Read a {@link TimestampedValue} from a parcel that was stored using
       * {@link #writeToParcel(Parcel, TimestampedValue)}.
       *
       * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
       * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
       * supported by those methods.
       *
       * @param in the Parcel to read from
       * @param classLoader the ClassLoader to pass to {@link Parcel#readValue(ClassLoader)}
       * @param valueClass the expected type of the value, typically the same as {@code <T>} but can
       *     also be a subclass
       * @throws RuntimeException if the value read is not compatible with {@code valueClass} or the
       *     object could not be read
       */
      @SuppressWarnings("unchecked")
      @NonNull
      public static <T> TimestampedValue<T> readFromParcel(
              @NonNull Parcel in, @Nullable ClassLoader classLoader, Class<? extends T> valueClass) {
          long referenceTimeMillis = in.readLong();
          T value = (T) in.readValue(classLoader);
          // Equivalent to static code: if (!(value.getClass() instanceof {valueClass})) {
          if (value != null && !valueClass.isAssignableFrom(value.getClass())) {
              throw new RuntimeException("Value was of type " + value.getClass()
                      + " is not assignable to " + valueClass);
          }
          return new TimestampedValue<>(referenceTimeMillis, value);
      }
  
      /**
       * Write a {@link TimestampedValue} to a parcel so that it can be read using
       * {@link #readFromParcel(Parcel, ClassLoader, Class)}.
       *
       * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
       * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
       * supported by those methods.
       *
       * @param dest the Parcel
       * @param timestampedValue the value
       * @throws RuntimeException if the value could not be written to the Parcel
       */
      public static void writeToParcel(
              @NonNull Parcel dest, @NonNull TimestampedValue<?> timestampedValue) {
          dest.writeLong(timestampedValue.mReferenceTimeMillis);
          dest.writeValue(timestampedValue.mValue);
      }
  
      /**
       * Returns the difference in milliseconds between two instance's reference times.
       */
      public static long referenceTimeDifference(
              @NonNull TimestampedValue<?> one, @NonNull TimestampedValue<?> two) {
          return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
      }
  }
  