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

Commit 4ef2551d authored by Neil Fuller's avatar Neil Fuller Committed by Gerrit Code Review
Browse files

Merge "Make TimeDetectorService more aware of origin"

parents 217e42aa af3eeaf4
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package android.app.timedetector;

import android.app.timedetector.TimeSignal;
import android.app.timedetector.PhoneTimeSuggestion;

/**
 * System private API to comunicate with time detector service.
 * System private API to communicate with time detector service.
 *
 * <p>Used by parts of the Android system with signals associated with the device's time to provide
 * information to the Time Detector Service.
@@ -32,5 +32,5 @@ import android.app.timedetector.TimeSignal;
 * {@hide}
 */
interface ITimeDetectorService {
  void suggestTime(in TimeSignal timeSignal);
  void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
}
+1 −1
Original line number Diff line number Diff line
@@ -16,4 +16,4 @@

package android.app.timedetector;

parcelable TimeSignal;
 No newline at end of file
parcelable PhoneTimeSuggestion;
+137 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 * Copyright (C) 2019 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.
@@ -17,47 +17,57 @@
package android.app.timedetector;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimestampedValue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * A time signal from a named source. The value consists of the number of milliseconds elapsed since
 * 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number was
 * established. The elapsed realtime clock is considered accurate but volatile, so time signals
 * A time signal from a telephony source. The value consists of the number of milliseconds elapsed
 * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
 * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
 * must not be persisted across device resets.
 *
 * @hide
 */
public final class TimeSignal implements Parcelable {
public final class PhoneTimeSuggestion implements Parcelable {

    public static final @android.annotation.NonNull Parcelable.Creator<TimeSignal> CREATOR =
            new Parcelable.Creator<TimeSignal>() {
                public TimeSignal createFromParcel(Parcel in) {
                    return TimeSignal.createFromParcel(in);
    public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
            new Parcelable.Creator<PhoneTimeSuggestion>() {
                public PhoneTimeSuggestion createFromParcel(Parcel in) {
                    return PhoneTimeSuggestion.createFromParcel(in);
                }

                public TimeSignal[] newArray(int size) {
                    return new TimeSignal[size];
                public PhoneTimeSuggestion[] newArray(int size) {
                    return new PhoneTimeSuggestion[size];
                }
            };

    public static final String SOURCE_ID_NITZ = "nitz";

    private final String mSourceId;
    private final int mPhoneId;
    @NonNull
    private final TimestampedValue<Long> mUtcTime;
    @Nullable
    private ArrayList<String> mDebugInfo;

    public TimeSignal(String sourceId, TimestampedValue<Long> utcTime) {
        mSourceId = Objects.requireNonNull(sourceId);
    public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
        mPhoneId = phoneId;
        mUtcTime = Objects.requireNonNull(utcTime);
    }

    private static TimeSignal createFromParcel(Parcel in) {
        String sourceId = in.readString();
    private static PhoneTimeSuggestion createFromParcel(Parcel in) {
        int phoneId = in.readInt();
        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
        return new TimeSignal(sourceId, utcTime);
        PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
        @SuppressWarnings("unchecked")
        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
        suggestion.mDebugInfo = debugInfo;
        return suggestion;
    }

    @Override
@@ -67,13 +77,13 @@ public final class TimeSignal implements Parcelable {

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(mSourceId);
        dest.writeInt(mPhoneId);
        dest.writeParcelable(mUtcTime, 0);
        dest.writeList(mDebugInfo);
    }

    @NonNull
    public String getSourceId() {
        return mSourceId;
    public int getPhoneId() {
        return mPhoneId;
    }

    @NonNull
@@ -81,6 +91,23 @@ public final class TimeSignal implements Parcelable {
        return mUtcTime;
    }

    @NonNull
    public List<String> getDebugInfo() {
        return Collections.unmodifiableList(mDebugInfo);
    }

    /**
     * Associates information with the instance that can be useful for debugging / logging. The
     * information is present in {@link #toString()} but is not considered for
     * {@link #equals(Object)} and {@link #hashCode()}.
     */
    public void addDebugInfo(String... debugInfos) {
        if (mDebugInfo == null) {
            mDebugInfo = new ArrayList<>();
        }
        mDebugInfo.addAll(Arrays.asList(debugInfos));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
@@ -89,21 +116,22 @@ public final class TimeSignal implements Parcelable {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        TimeSignal that = (TimeSignal) o;
        return Objects.equals(mSourceId, that.mSourceId)
        PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
        return mPhoneId == that.mPhoneId
                && Objects.equals(mUtcTime, that.mUtcTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mSourceId, mUtcTime);
        return Objects.hash(mPhoneId, mUtcTime);
    }

    @Override
    public String toString() {
        return "TimeSignal{"
                + "mSourceId='" + mSourceId + '\''
        return "PhoneTimeSuggestion{"
                + "mPhoneId='" + mPhoneId + '\''
                + ", mUtcTime=" + mUtcTime
                + ", mDebugInfo=" + mDebugInfo
                + '}';
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -45,12 +45,12 @@ public final class TimeDetector {
     * signals are available such as those that come from more reliable sources or were
     * determined more recently.
     */
    public void suggestTime(@NonNull TimeSignal timeSignal) {
    public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
        if (DEBUG) {
            Log.d(TAG, "suggestTime called: " + timeSignal);
            Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
        }
        try {
            mITimeDetectorService.suggestTime(timeSignal);
            mITimeDetectorService.suggestPhoneTime(timeSuggestion);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.app.timedetector;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimestampedValue;

import org.junit.Test;

public class PhoneTimeSuggestionTest {
    private static final int PHONE_ID = 99999;

    @Test
    public void testEquals() {
        PhoneTimeSuggestion one =
                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
        assertEquals(one, one);

        PhoneTimeSuggestion two =
                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
        assertEquals(one, two);
        assertEquals(two, one);

        PhoneTimeSuggestion three =
                new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
        assertNotEquals(one, three);
        assertNotEquals(three, one);

        // DebugInfo must not be considered in equals().
        one.addDebugInfo("Debug info 1");
        two.addDebugInfo("Debug info 2");
        assertEquals(one, two);
    }

    @Test
    public void testParcelable() {
        PhoneTimeSuggestion one =
                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
        assertEquals(one, roundTripParcelable(one));

        // DebugInfo should also be stored (but is not checked by equals()
        one.addDebugInfo("This is debug info");
        PhoneTimeSuggestion two = roundTripParcelable(one);
        assertEquals(one.getDebugInfo(), two.getDebugInfo());
    }

    @SuppressWarnings("unchecked")
    private static <T extends Parcelable> T roundTripParcelable(T one) {
        Parcel parcel = Parcel.obtain();
        parcel.writeTypedObject(one, 0);
        parcel.setDataPosition(0);

        T toReturn = (T) parcel.readTypedObject(PhoneTimeSuggestion.CREATOR);
        parcel.recycle();
        return toReturn;
    }
}
Loading