Merge "Add a new method to set time"
am: 5f01cb6ddc
Change-Id: If92a40f84971a663f99d7d764cd45e8d3510bfda
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app.timedetector;
|
||||
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
|
||||
/**
|
||||
@@ -33,4 +34,5 @@ import android.app.timedetector.PhoneTimeSuggestion;
|
||||
*/
|
||||
interface ITimeDetectorService {
|
||||
void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
|
||||
void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
|
||||
}
|
||||
|
||||
19
core/java/android/app/timedetector/ManualTimeSuggestion.aidl
Normal file
19
core/java/android/app/timedetector/ManualTimeSuggestion.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
parcelable ManualTimeSuggestion;
|
||||
127
core/java/android/app/timedetector/ManualTimeSuggestion.java
Normal file
127
core/java/android/app/timedetector/ManualTimeSuggestion.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 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 manual (user provided) 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 ManualTimeSuggestion implements Parcelable {
|
||||
|
||||
public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
|
||||
new Creator<ManualTimeSuggestion>() {
|
||||
public ManualTimeSuggestion createFromParcel(Parcel in) {
|
||||
return ManualTimeSuggestion.createFromParcel(in);
|
||||
}
|
||||
|
||||
public ManualTimeSuggestion[] newArray(int size) {
|
||||
return new ManualTimeSuggestion[size];
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
private final TimestampedValue<Long> mUtcTime;
|
||||
@Nullable
|
||||
private ArrayList<String> mDebugInfo;
|
||||
|
||||
public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
|
||||
mUtcTime = Objects.requireNonNull(utcTime);
|
||||
}
|
||||
|
||||
private static ManualTimeSuggestion createFromParcel(Parcel in) {
|
||||
TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
|
||||
ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
|
||||
suggestion.mDebugInfo = debugInfo;
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mUtcTime, 0);
|
||||
dest.writeList(mDebugInfo);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public TimestampedValue<Long> getUtcTime() {
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ManualTimeSuggestion that = (ManualTimeSuggestion) o;
|
||||
return Objects.equals(mUtcTime, that.mUtcTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mUtcTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ManualTimeSuggestion{"
|
||||
+ "mUtcTime=" + mUtcTime
|
||||
+ ", mDebugInfo=" + mDebugInfo
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -17,19 +17,22 @@
|
||||
package android.app.timedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.util.TimestampedValue;
|
||||
|
||||
/**
|
||||
* The interface through which system components can send signals to the TimeDetectorService.
|
||||
* @hide
|
||||
*/
|
||||
@SystemService(Context.TIME_DETECTOR_SERVICE)
|
||||
public final class TimeDetector {
|
||||
public class TimeDetector {
|
||||
private static final String TAG = "timedetector.TimeDetector";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@@ -41,10 +44,11 @@ public final class TimeDetector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests the current time to the detector. The detector may ignore the signal if better
|
||||
* signals are available such as those that come from more reliable sources or were
|
||||
* determined more recently.
|
||||
* Suggests the current phone-signal derived time to the detector. The detector may ignore the
|
||||
* signal if better signals are available such as those that come from more reliable sources or
|
||||
* were determined more recently.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.SET_TIME)
|
||||
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
|
||||
@@ -56,4 +60,29 @@ public final class TimeDetector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests the user's manually entered current time to the detector.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.SET_TIME)
|
||||
public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
|
||||
}
|
||||
try {
|
||||
mITimeDetectorService.suggestManualTime(timeSuggestion);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A shared utility method to create a {@link ManualTimeSuggestion}.
|
||||
*/
|
||||
public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
|
||||
TimestampedValue<Long> utcTime =
|
||||
new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
|
||||
ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
|
||||
manualTimeSuggestion.addDebugInfo(why);
|
||||
return manualTimeSuggestion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.android.server.timedetector;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
import android.content.Intent;
|
||||
import android.util.Slog;
|
||||
@@ -27,6 +29,8 @@ import android.util.TimestampedValue;
|
||||
import com.android.internal.telephony.TelephonyIntents;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
|
||||
@@ -38,10 +42,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
|
||||
private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
|
||||
|
||||
@IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Origin {}
|
||||
|
||||
/** Used when a time value originated from a telephony signal. */
|
||||
@Origin
|
||||
private static final int ORIGIN_PHONE = 1;
|
||||
|
||||
/** Used when a time value originated from a user / manual settings. */
|
||||
@Origin
|
||||
private static final int ORIGIN_MANUAL = 2;
|
||||
|
||||
/**
|
||||
* CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
|
||||
* actual system clock time before a warning is logged. Used to help identify situations where
|
||||
* there is something other than this class setting the system clock.
|
||||
* there is something other than this class setting the system clock automatically.
|
||||
*/
|
||||
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
|
||||
|
||||
@@ -52,11 +68,11 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
@Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
|
||||
|
||||
// Information about the last time signal received: Used when toggling auto-time.
|
||||
@Nullable private TimestampedValue<Long> mLastSystemClockTime;
|
||||
private boolean mLastSystemClockTimeSendNetworkBroadcast;
|
||||
@Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
|
||||
private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
|
||||
|
||||
// System clock state.
|
||||
@Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
|
||||
@Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
|
||||
|
||||
@Override
|
||||
public void initialize(@NonNull Callback callback) {
|
||||
@@ -78,17 +94,18 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
return;
|
||||
}
|
||||
// Always store the last NITZ value received, regardless of whether we go on to use it to
|
||||
// update the system clock. This is so that we can validate future NITZ signals.
|
||||
// update the system clock. This is so that we can validate future phone suggestions.
|
||||
mLastPhoneSuggestion = timeSuggestion;
|
||||
|
||||
// System clock update logic.
|
||||
|
||||
// Historically, Android has sent a telephony broadcast only when setting the time using
|
||||
// NITZ.
|
||||
final boolean sendNetworkBroadcast = true;
|
||||
|
||||
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
|
||||
setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
|
||||
setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
|
||||
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
|
||||
setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
|
||||
}
|
||||
|
||||
private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
|
||||
@@ -110,16 +127,31 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
}
|
||||
|
||||
private void setSystemClockIfRequired(
|
||||
TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
|
||||
@Origin int origin, TimestampedValue<Long> time, Object cause) {
|
||||
// Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
|
||||
// when setting the time using NITZ.
|
||||
boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
|
||||
|
||||
// Store the last candidate we've seen in all cases so we can set the system clock
|
||||
// when/if time detection is enabled.
|
||||
mLastSystemClockTime = time;
|
||||
mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
|
||||
boolean isOriginAutomatic = isOriginAutomatic(origin);
|
||||
if (isOriginAutomatic) {
|
||||
// Store the last auto time candidate we've seen in all cases so we can set the system
|
||||
// clock when/if time detection is off but later enabled.
|
||||
mLastAutoSystemClockTime = time;
|
||||
mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
|
||||
|
||||
if (!mCallback.isTimeDetectionEnabled()) {
|
||||
Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
|
||||
return;
|
||||
if (!mCallback.isAutoTimeDetectionEnabled()) {
|
||||
Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is not enabled."
|
||||
+ " time=" + time
|
||||
+ ", cause=" + cause);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (mCallback.isAutoTimeDetectionEnabled()) {
|
||||
Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is enabled."
|
||||
+ " time=" + time
|
||||
+ ", cause=" + cause);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mCallback.acquireWakeLock();
|
||||
@@ -127,37 +159,44 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
|
||||
long actualTimeMillis = mCallback.systemClockMillis();
|
||||
|
||||
// CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
|
||||
// may be setting the clock.
|
||||
if (mLastSystemClockTimeSet != null) {
|
||||
long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
|
||||
mLastSystemClockTimeSet, elapsedRealtimeMillis);
|
||||
long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
|
||||
if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
|
||||
Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
|
||||
+ " be inaccurate or something unexpectedly set the system clock."
|
||||
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
|
||||
+ " expectedTimeMillis=" + expectedTimeMillis
|
||||
+ " actualTimeMillis=" + actualTimeMillis);
|
||||
if (isOriginAutomatic) {
|
||||
// CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
|
||||
// may be setting the clock.
|
||||
if (mLastAutoSystemClockTimeSet != null) {
|
||||
long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
|
||||
mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
|
||||
long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
|
||||
if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
|
||||
Slog.w(TAG,
|
||||
"System clock has not tracked elapsed real time clock. A clock may"
|
||||
+ " be inaccurate or something unexpectedly set the system"
|
||||
+ " clock."
|
||||
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
|
||||
+ " expectedTimeMillis=" + expectedTimeMillis
|
||||
+ " actualTimeMillis=" + actualTimeMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String reason = "New time signal";
|
||||
adjustAndSetDeviceSystemClock(
|
||||
time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
|
||||
time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
|
||||
} finally {
|
||||
mCallback.releaseWakeLock();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isOriginAutomatic(@Origin int origin) {
|
||||
return origin == ORIGIN_PHONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAutoTimeDetectionToggle(boolean enabled) {
|
||||
// If automatic time detection is enabled we update the system clock instantly if we can.
|
||||
// Conversely, if automatic time detection is disabled we leave the clock as it is.
|
||||
if (enabled) {
|
||||
if (mLastSystemClockTime != null) {
|
||||
if (mLastAutoSystemClockTime != null) {
|
||||
// Only send the network broadcast if the last candidate would have caused one.
|
||||
final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
|
||||
final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
|
||||
|
||||
mCallback.acquireWakeLock();
|
||||
try {
|
||||
@@ -165,7 +204,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
long actualTimeMillis = mCallback.systemClockMillis();
|
||||
|
||||
final String reason = "Automatic time detection enabled.";
|
||||
adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
|
||||
adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
|
||||
elapsedRealtimeMillis, actualTimeMillis, reason);
|
||||
} finally {
|
||||
mCallback.releaseWakeLock();
|
||||
@@ -174,22 +213,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
} else {
|
||||
// CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
|
||||
// it should be in future.
|
||||
mLastSystemClockTimeSet = null;
|
||||
mLastAutoSystemClockTimeSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
|
||||
pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
|
||||
pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
|
||||
pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
|
||||
pw.println("mLastSystemClockTimeSendNetworkBroadcast="
|
||||
+ mLastSystemClockTimeSendNetworkBroadcast);
|
||||
pw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
|
||||
pw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
|
||||
pw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
|
||||
+ mLastAutoSystemClockTimeSendNetworkBroadcast);
|
||||
}
|
||||
|
||||
private void adjustAndSetDeviceSystemClock(
|
||||
TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
|
||||
long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
|
||||
long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
|
||||
|
||||
// Adjust for the time that has elapsed since the signal was received.
|
||||
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
|
||||
@@ -203,20 +242,20 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
+ " system clock are close enough."
|
||||
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
|
||||
+ " newTime=" + newTime
|
||||
+ " reason=" + reason
|
||||
+ " cause=" + cause
|
||||
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
|
||||
+ " absTimeDifference=" + absTimeDifference);
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.d(TAG, "Setting system clock using time=" + newTime
|
||||
+ " reason=" + reason
|
||||
+ " cause=" + cause
|
||||
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
|
||||
+ " newTimeMillis=" + newSystemClockMillis);
|
||||
mCallback.setSystemClock(newSystemClockMillis);
|
||||
|
||||
// CLOCK_PARANOIA : Record the last time this class set the system clock.
|
||||
mLastSystemClockTimeSet = newTime;
|
||||
mLastAutoSystemClockTimeSet = newTime;
|
||||
|
||||
if (sendNetworkBroadcast) {
|
||||
// Send a broadcast that telephony code used to send after setting the clock.
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.timedetector;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.timedetector.ITimeDetectorService;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -97,7 +98,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
|
||||
|
||||
@Override
|
||||
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
|
||||
enforceSetTimePermission();
|
||||
enforceSuggestPhoneTimePermission();
|
||||
Objects.requireNonNull(timeSignal);
|
||||
|
||||
long idToken = Binder.clearCallingIdentity();
|
||||
@@ -110,10 +111,25 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) {
|
||||
enforceSuggestManualTimePermission();
|
||||
Objects.requireNonNull(timeSignal);
|
||||
|
||||
long idToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mStrategyLock) {
|
||||
mTimeDetectorStrategy.suggestManualTime(timeSignal);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(idToken);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void handleAutoTimeDetectionToggle() {
|
||||
synchronized (mStrategyLock) {
|
||||
final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
|
||||
final boolean timeDetectionEnabled = mCallback.isAutoTimeDetectionEnabled();
|
||||
mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
|
||||
}
|
||||
}
|
||||
@@ -128,7 +144,11 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceSetTimePermission() {
|
||||
private void enforceSuggestPhoneTimePermission() {
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceSuggestManualTimePermission() {
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.timedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
import android.content.Intent;
|
||||
import android.util.TimestampedValue;
|
||||
@@ -47,7 +48,7 @@ public interface TimeDetectorStrategy {
|
||||
int systemClockUpdateThresholdMillis();
|
||||
|
||||
/** Returns true if automatic time detection is enabled. */
|
||||
boolean isTimeDetectionEnabled();
|
||||
boolean isAutoTimeDetectionEnabled();
|
||||
|
||||
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
|
||||
void acquireWakeLock();
|
||||
@@ -71,9 +72,12 @@ public interface TimeDetectorStrategy {
|
||||
/** Initialize the strategy. */
|
||||
void initialize(@NonNull Callback callback);
|
||||
|
||||
/** Process the suggested time. */
|
||||
/** Process the suggested time from telephony sources. */
|
||||
void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
|
||||
|
||||
/** Process the suggested manually entered time. */
|
||||
void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
|
||||
|
||||
/** Handle the auto-time setting being toggled on or off. */
|
||||
void handleAutoTimeDetectionToggle(boolean enabled);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTimeDetectionEnabled() {
|
||||
public boolean isAutoTimeDetectionEnabled() {
|
||||
try {
|
||||
return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
|
||||
} catch (Settings.SettingNotFoundException snfe) {
|
||||
|
||||
@@ -133,6 +133,8 @@ import android.app.admin.StartInstallingUpdateCallback;
|
||||
import android.app.admin.SystemUpdateInfo;
|
||||
import android.app.admin.SystemUpdatePolicy;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.ActivityNotFoundException;
|
||||
@@ -1950,6 +1952,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
return mContext.getSystemService(AlarmManager.class);
|
||||
}
|
||||
|
||||
TimeDetector getTimeDetector() {
|
||||
return mContext.getSystemService(TimeDetector.class);
|
||||
}
|
||||
|
||||
ConnectivityManager getConnectivityManager() {
|
||||
return mContext.getSystemService(ConnectivityManager.class);
|
||||
}
|
||||
@@ -10859,7 +10865,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
|
||||
return false;
|
||||
}
|
||||
mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
|
||||
ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
|
||||
millis, "DevicePolicyManagerService: setTime");
|
||||
mInjector.binderWithCleanCallingIdentity(
|
||||
() -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.app.IActivityTaskManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -216,6 +217,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
|
||||
@Override
|
||||
AlarmManager getAlarmManager() {return services.alarmManager;}
|
||||
|
||||
@Override
|
||||
TimeDetector getTimeDetector() {
|
||||
return services.timeDetector;
|
||||
}
|
||||
|
||||
@Override
|
||||
LockPatternUtils newLockPatternUtils() {
|
||||
return services.lockPatternUtils;
|
||||
|
||||
@@ -63,6 +63,7 @@ import android.app.admin.DeviceAdminReceiver;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.PasswordMetrics;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
@@ -3473,7 +3474,19 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
|
||||
setupDeviceOwner();
|
||||
dpm.setTime(admin1, 0);
|
||||
verify(getServices().alarmManager).setTime(0);
|
||||
|
||||
BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
|
||||
return suggestion.getUtcTime().getValue() == 0;
|
||||
}
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("ManualTimeSuggestion{utcTime.value=0}");
|
||||
}
|
||||
};
|
||||
verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
|
||||
}
|
||||
|
||||
public void testSetTimeFailWithPO() throws Exception {
|
||||
|
||||
@@ -207,6 +207,8 @@ public class DpmMockContext extends MockContext {
|
||||
switch (name) {
|
||||
case Context.ALARM_SERVICE:
|
||||
return mMockSystemServices.alarmManager;
|
||||
case Context.TIME_DETECTOR_SERVICE:
|
||||
return mMockSystemServices.timeDetector;
|
||||
case Context.USER_SERVICE:
|
||||
return mMockSystemServices.userManager;
|
||||
case Context.POWER_SERVICE:
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.app.IActivityManager;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
@@ -107,6 +108,7 @@ public class MockSystemServices {
|
||||
public final TelephonyManager telephonyManager;
|
||||
public final AccountManager accountManager;
|
||||
public final AlarmManager alarmManager;
|
||||
public final TimeDetector timeDetector;
|
||||
public final KeyChain.KeyChainConnection keyChainConnection;
|
||||
/** Note this is a partial mock, not a real mock. */
|
||||
public final PackageManager packageManager;
|
||||
@@ -146,6 +148,7 @@ public class MockSystemServices {
|
||||
telephonyManager = mock(TelephonyManager.class);
|
||||
accountManager = mock(AccountManager.class);
|
||||
alarmManager = mock(AlarmManager.class);
|
||||
timeDetector = mock(TimeDetector.class);
|
||||
keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
|
||||
|
||||
// Package manager is huge, so we use a partial mock instead.
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
import android.content.Intent;
|
||||
import android.icu.util.Calendar;
|
||||
@@ -36,6 +37,8 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
@@ -47,6 +50,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
private static final int ARBITRARY_PHONE_ID = 123456;
|
||||
|
||||
private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis();
|
||||
|
||||
private Script mScript;
|
||||
|
||||
@Before
|
||||
@@ -55,7 +60,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
|
||||
public void testSuggestPhoneTime_autoTimeEnabled() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
.pokeTimeDetectionEnabled(true);
|
||||
@@ -67,7 +72,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
mScript.simulateTimePassing(clockIncrement)
|
||||
.simulatePhoneTimeSuggestion(timeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectSystemClockMillis, true /* expectNetworkBroadcast */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,7 +109,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
// Send the first time signal. It should be used.
|
||||
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectSystemClockMillis1, true /* expectNetworkBroadcast */);
|
||||
|
||||
// Now send another time signal, but one that is too similar to the last one and should be
|
||||
// ignored.
|
||||
@@ -130,11 +137,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
|
||||
|
||||
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectSystemClockMillis3, true /* expectNetworkBroadcast */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
|
||||
public void testSuggestPhoneTime_autoTimeDisabled() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
.pokeTimeDetectionEnabled(false);
|
||||
@@ -146,7 +154,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
|
||||
public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
final int systemClockUpdateThreshold = 2000;
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
@@ -161,7 +169,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
long expectedSystemClockMillis1 =
|
||||
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
|
||||
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
|
||||
|
||||
// The UTC time increment should be larger than the system clock update threshold so we
|
||||
// know it shouldn't be ignored for other reasons.
|
||||
@@ -197,7 +206,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
PhoneTimeSuggestion timeSuggestion4 =
|
||||
createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
|
||||
mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -229,7 +239,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
// Turn on auto time detection.
|
||||
mScript.simulateAutoTimeDetectionToggle()
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
|
||||
|
||||
// Turn off auto time detection.
|
||||
mScript.simulateAutoTimeDetectionToggle()
|
||||
@@ -256,7 +267,99 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
|
||||
// Turn on auto time detection.
|
||||
mScript.simulateAutoTimeDetectionToggle()
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestManualTime_autoTimeDisabled() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
.pokeTimeDetectionEnabled(false);
|
||||
|
||||
ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
|
||||
final int clockIncrement = 1000;
|
||||
long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
|
||||
|
||||
mScript.simulateTimePassing(clockIncrement)
|
||||
.simulateManualTimeSuggestion(timeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectSystemClockMillis, false /* expectNetworkBroadcast */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestManualTime_retainsAutoSignal() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
|
||||
// Configure the start state.
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
.pokeTimeDetectionEnabled(true);
|
||||
|
||||
// Simulate a phone suggestion.
|
||||
PhoneTimeSuggestion phoneTimeSuggestion =
|
||||
scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
|
||||
long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
|
||||
final int clockIncrement = 1000;
|
||||
|
||||
// Simulate the passage of time.
|
||||
mScript.simulateTimePassing(clockIncrement);
|
||||
expectedAutoClockMillis += clockIncrement;
|
||||
|
||||
mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedAutoClockMillis, true /* expectNetworkBroadcast */);
|
||||
|
||||
// Simulate the passage of time.
|
||||
mScript.simulateTimePassing(clockIncrement);
|
||||
expectedAutoClockMillis += clockIncrement;
|
||||
|
||||
// Switch to manual.
|
||||
mScript.simulateAutoTimeDetectionToggle()
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
|
||||
// Simulate the passage of time.
|
||||
mScript.simulateTimePassing(clockIncrement);
|
||||
expectedAutoClockMillis += clockIncrement;
|
||||
|
||||
|
||||
// Simulate a manual suggestion 1 day different from the auto suggestion.
|
||||
long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
|
||||
long expectedManualClockMillis = manualTimeMillis;
|
||||
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
|
||||
mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedManualClockMillis, false /* expectNetworkBroadcast */);
|
||||
|
||||
// Simulate the passage of time.
|
||||
mScript.simulateTimePassing(clockIncrement);
|
||||
expectedAutoClockMillis += clockIncrement;
|
||||
|
||||
// Switch back to auto.
|
||||
mScript.simulateAutoTimeDetectionToggle();
|
||||
|
||||
mScript.verifySystemClockWasSetAndResetCallTracking(
|
||||
expectedAutoClockMillis, true /* expectNetworkBroadcast */);
|
||||
|
||||
// Switch back to manual - nothing should happen to the clock.
|
||||
mScript.simulateAutoTimeDetectionToggle()
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual suggestions should be ignored if auto time is enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSuggestManualTime_autoTimeEnabled() {
|
||||
Scenario scenario = SCENARIO_1;
|
||||
mScript.pokeFakeClocks(scenario)
|
||||
.pokeTimeDetectionEnabled(true);
|
||||
|
||||
ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
|
||||
final int clockIncrement = 1000;
|
||||
|
||||
mScript.simulateTimePassing(clockIncrement)
|
||||
.simulateManualTimeSuggestion(timeSuggestion)
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,7 +383,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTimeDetectionEnabled() {
|
||||
public boolean isAutoTimeDetectionEnabled() {
|
||||
return mTimeDetectionEnabled;
|
||||
}
|
||||
|
||||
@@ -426,8 +529,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
|
||||
mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
|
||||
return this;
|
||||
}
|
||||
|
||||
Script simulateAutoTimeDetectionToggle() {
|
||||
boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
|
||||
boolean enabled = !mFakeCallback.isAutoTimeDetectionEnabled();
|
||||
mFakeCallback.pokeTimeDetectionEnabled(enabled);
|
||||
mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
|
||||
return this;
|
||||
@@ -445,9 +553,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
|
||||
Script verifySystemClockWasSetAndResetCallTracking(
|
||||
long expectSystemClockMillis, boolean expectNetworkBroadcast) {
|
||||
mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
|
||||
mFakeCallback.verifyIntentWasBroadcast();
|
||||
if (expectNetworkBroadcast) {
|
||||
mFakeCallback.verifyIntentWasBroadcast();
|
||||
}
|
||||
mFakeCallback.resetCallTracking();
|
||||
return this;
|
||||
}
|
||||
@@ -486,6 +597,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
return createPhoneTimeSuggestion(phoneId, time);
|
||||
}
|
||||
|
||||
ManualTimeSuggestion createManualTimeSuggestionForActual() {
|
||||
TimestampedValue<Long> time = new TimestampedValue<>(
|
||||
mInitialDeviceRealtimeMillis, mActualTimeMillis);
|
||||
return new ManualTimeSuggestion(time);
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
|
||||
private long mInitialDeviceSystemClockMillis;
|
||||
@@ -525,6 +642,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
|
||||
return timeSuggestion;
|
||||
}
|
||||
|
||||
private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
|
||||
TimestampedValue<Long> utcTime =
|
||||
new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
|
||||
return new ManualTimeSuggestion(utcTime);
|
||||
}
|
||||
|
||||
private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
|
||||
int second) {
|
||||
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
|
||||
|
||||
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.PhoneTimeSuggestion;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -89,6 +90,19 @@ public class TimeDetectorServiceTest {
|
||||
mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestManualTime() {
|
||||
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
|
||||
mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.SET_TIME),
|
||||
anyString());
|
||||
mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDump() {
|
||||
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
|
||||
@@ -102,13 +116,13 @@ public class TimeDetectorServiceTest {
|
||||
|
||||
@Test
|
||||
public void testAutoTimeDetectionToggle() {
|
||||
when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
|
||||
when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(true);
|
||||
|
||||
mTimeDetectorService.handleAutoTimeDetectionToggle();
|
||||
|
||||
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
|
||||
|
||||
when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
|
||||
when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(false);
|
||||
|
||||
mTimeDetectorService.handleAutoTimeDetectionToggle();
|
||||
|
||||
@@ -123,10 +137,16 @@ public class TimeDetectorServiceTest {
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
private static ManualTimeSuggestion createManualTimeSuggestion() {
|
||||
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
|
||||
return new ManualTimeSuggestion(timeValue);
|
||||
}
|
||||
|
||||
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
|
||||
// Call tracking.
|
||||
private PhoneTimeSuggestion mLastPhoneSuggestion;
|
||||
private ManualTimeSuggestion mLastManualSuggestion;
|
||||
private Boolean mLastAutoTimeDetectionToggle;
|
||||
private boolean mDumpCalled;
|
||||
|
||||
@@ -140,6 +160,12 @@ public class TimeDetectorServiceTest {
|
||||
mLastPhoneSuggestion = timeSuggestion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
|
||||
resetCallTracking();
|
||||
mLastManualSuggestion = timeSuggestion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAutoTimeDetectionToggle(boolean enabled) {
|
||||
resetCallTracking();
|
||||
@@ -154,12 +180,17 @@ public class TimeDetectorServiceTest {
|
||||
|
||||
void resetCallTracking() {
|
||||
mLastPhoneSuggestion = null;
|
||||
mLastManualSuggestion = null;
|
||||
mLastAutoTimeDetectionToggle = null;
|
||||
mDumpCalled = false;
|
||||
}
|
||||
|
||||
void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
|
||||
assertEquals(expectedSignal, mLastPhoneSuggestion);
|
||||
void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSuggestion) {
|
||||
assertEquals(expectedSuggestion, mLastPhoneSuggestion);
|
||||
}
|
||||
|
||||
public void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
|
||||
assertEquals(expectedSuggestion, mLastManualSuggestion);
|
||||
}
|
||||
|
||||
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
|
||||
|
||||
Reference in New Issue
Block a user