summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Neil Fuller <nfuller@google.com> 2019-11-28 00:54:46 -0800
committer android-build-merger <android-build-merger@google.com> 2019-11-28 00:54:46 -0800
commitb07f90adb8d88cb84b5d52d39eace93594846865 (patch)
treec87e95a1a2f3db85f598976d6bc36677299bddf9
parent0a1aca082c36e997477eb2d7cd6cef1cd9179597 (diff)
parent5f01cb6ddca16e231c9ce57baa6949c075b3cc05 (diff)
Merge "Add a new method to set time"
am: 5f01cb6ddc Change-Id: If92a40f84971a663f99d7d764cd45e8d3510bfda
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl2
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.aidl19
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java127
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java37
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java131
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java28
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java8
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java151
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java39
15 files changed, 504 insertions, 77 deletions
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index ddc4932d6fec..9877fc741b7b 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -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);
}
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.aidl b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
new file mode 100644
index 000000000000..213940493114
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
@@ -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;
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
new file mode 100644
index 000000000000..e7d619a27607
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -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
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 334e9582a145..48d5cd2d65a5 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -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;
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index fd8cc24b658b..3c79b2399fa3 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -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.
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
+ setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
+ }
- // Historically, Android has sent a telephony broadcast only when setting the time using
- // NITZ.
- final boolean sendNetworkBroadcast = true;
-
+ @Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
- setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+ 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) {
-
- // 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;
-
- if (!mCallback.isTimeDetectionEnabled()) {
- Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
- return;
+ @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;
+
+ 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.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.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index ee42279f7d50..09309751d493 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -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");
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 7c2a945854f5..b60cebf57b45 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -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);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 77b9e6281086..42d59d51c6af 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -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) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2e56fb096e3b..e8617bce920e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -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;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 2ce4c54a932b..0fde850d3021 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -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;
@@ -217,6 +218,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
AlarmManager getAlarmManager() {return services.alarmManager;}
@Override
+ TimeDetector getTimeDetector() {
+ return services.timeDetector;
+ }
+
+ @Override
LockPatternUtils newLockPatternUtils() {
return services.lockPatternUtils;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 9ae9824da3e2..b93b47ad74bd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -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 {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bd513dc083be..1a67576c218f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -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:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 8f0aeea3dbf8..b208f828ee85 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -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.
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index b49845ae4006..317fd4d566ae 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -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"));
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index cfd8a457d2f0..4efe771a4e95 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -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;
@@ -90,6 +91,19 @@ public class TimeDetectorServiceTest {
}
@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))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -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;
@@ -141,6 +161,12 @@ public class TimeDetectorServiceTest {
}
@Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+ resetCallTracking();
+ mLastManualSuggestion = timeSuggestion;
+ }
+
+ @Override
public void handleAutoTimeDetectionToggle(boolean enabled) {
resetCallTracking();
mLastAutoTimeDetectionToggle = enabled;
@@ -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) {