Merge "Add internal service paths for enterprise setup"

This commit is contained in:
Neil Fuller
2022-10-11 16:08:26 +00:00
committed by Android (Google) Code Review
30 changed files with 995 additions and 552 deletions

View File

@@ -155,21 +155,33 @@ public final class ConfigurationInternal {
return UserHandle.of(mUserId);
}
/** Returns true if the user allowed to modify time zone configuration. */
/**
* Returns true if the user is allowed to modify time configuration, e.g. can be false due
* to device policy (enterprise).
*
* <p>See also {@link #createCapabilitiesAndConfig(boolean)} for situations where this
* value are ignored.
*/
public boolean isUserConfigAllowed() {
return mUserConfigAllowed;
}
/** Returns a {@link TimeCapabilitiesAndConfig} objects based on configuration values. */
public TimeCapabilitiesAndConfig capabilitiesAndConfig() {
return new TimeCapabilitiesAndConfig(timeCapabilities(), timeConfiguration());
/**
* Returns a {@link TimeCapabilitiesAndConfig} objects based on configuration values.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
public TimeCapabilitiesAndConfig createCapabilitiesAndConfig(boolean bypassUserPolicyChecks) {
return new TimeCapabilitiesAndConfig(
timeCapabilities(bypassUserPolicyChecks), timeConfiguration());
}
private TimeCapabilities timeCapabilities() {
private TimeCapabilities timeCapabilities(boolean bypassUserPolicyChecks) {
UserHandle userHandle = UserHandle.of(mUserId);
TimeCapabilities.Builder builder = new TimeCapabilities.Builder(userHandle);
boolean allowConfigDateTime = isUserConfigAllowed();
boolean allowConfigDateTime = isUserConfigAllowed() || bypassUserPolicyChecks;
boolean deviceHasAutoTimeDetection = isAutoDetectionSupported();
final @CapabilityState int configureAutoDetectionEnabledCapability;
@@ -186,15 +198,15 @@ public final class ConfigurationInternal {
// current logic above, this could lead to a situation where a device hardware does not
// support auto detection, the device has been forced into "auto" mode by an admin and the
// user is unable to disable auto detection.
final @CapabilityState int suggestManualTimeZoneCapability;
final @CapabilityState int suggestManualTimeCapability;
if (!allowConfigDateTime) {
suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
suggestManualTimeCapability = CAPABILITY_NOT_ALLOWED;
} else if (getAutoDetectionEnabledBehavior()) {
suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
suggestManualTimeCapability = CAPABILITY_NOT_APPLICABLE;
} else {
suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
suggestManualTimeCapability = CAPABILITY_POSSESSED;
}
builder.setSetManualTimeCapability(suggestManualTimeZoneCapability);
builder.setSetManualTimeCapability(suggestManualTimeCapability);
return builder.build();
}

View File

@@ -53,11 +53,15 @@ public interface ServiceConfigAccessor {
/**
* Updates the configuration properties that control a device's time behavior.
*
* <p>This method returns {@code true} if the configuration was changed,
* {@code false} otherwise.
* <p>This method returns {@code true} if the configuration was changed, {@code false}
* otherwise.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
boolean updateConfiguration(
@UserIdInt int userId, @NonNull TimeConfiguration requestedConfiguration);
@UserIdInt int userId, @NonNull TimeConfiguration requestedConfiguration,
boolean bypassUserPolicyChecks);
/**
* Returns a snapshot of the configuration that controls time zone detector behavior for the

View File

@@ -194,11 +194,11 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
@Override
public synchronized boolean updateConfiguration(@UserIdInt int userId,
@NonNull TimeConfiguration requestedConfiguration) {
@NonNull TimeConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) {
Objects.requireNonNull(requestedConfiguration);
TimeCapabilitiesAndConfig capabilitiesAndConfig =
getCurrentUserConfigurationInternal().capabilitiesAndConfig();
TimeCapabilitiesAndConfig capabilitiesAndConfig = getCurrentUserConfigurationInternal()
.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();

View File

@@ -17,16 +17,47 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.ManualTimeSuggestion;
/**
* The internal (in-process) system server API for the {@link
* com.android.server.timedetector.TimeDetectorService}.
* The internal (in-process) system server API for the time detector service.
*
* <p>The methods on this class can be called from any thread.
*
* <p>Methods marked with "[For device policy manager only]" are for use by the device policy
* manager to set device state and must not enforce device policy restrictions.
*
* @hide
*/
public interface TimeDetectorInternal {
/**
* [For device policy manager only] Returns a snapshot of the configuration that controls time
* detector behavior for the current user.
*/
@NonNull
TimeCapabilitiesAndConfig getCapabilitiesAndConfigForDpm();
/**
* [For device policy manager only] Updates the configuration properties that control a device's
* time behavior for the current user.
*
* <p>This method returns {@code true} if the configuration was changed, {@code false}
* otherwise.
*/
boolean updateConfigurationForDpm(@NonNull TimeConfiguration configuration);
/**
* [For device policy manager only] Attempts to set the device to a manually entered time.
* Returns {@code false} if the suggestion is invalid, or the device configuration prevents the
* suggestion being used, {@code true} if the suggestion has been accepted. A suggestion that is
* valid but does not change the time because it matches the current device time is considered
* accepted.
*/
boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion manualTimeSuggestion);
/** Used to pass new network time suggestions to the time detector. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal);

View File

@@ -17,9 +17,14 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.ManualTimeSuggestion;
import android.content.Context;
import android.os.Handler;
import com.android.server.timezonedetector.CurrentUserIdentityInjector;
import java.util.Objects;
/**
@@ -31,15 +36,49 @@ public class TimeDetectorInternalImpl implements TimeDetectorInternal {
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
@NonNull private final CurrentUserIdentityInjector mCurrentUserIdentityInjector;
@NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
public TimeDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull CurrentUserIdentityInjector currentUserIdentityInjector,
@NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mCurrentUserIdentityInjector = Objects.requireNonNull(currentUserIdentityInjector);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
}
@Override
@NonNull
public TimeCapabilitiesAndConfig getCapabilitiesAndConfigForDpm() {
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyCheck = true;
ConfigurationInternal configurationInternal =
mServiceConfigAccessor.getConfigurationInternal(currentUserId);
return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyCheck);
}
@Override
public boolean updateConfigurationForDpm(@NonNull TimeConfiguration configuration) {
Objects.requireNonNull(configuration);
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyCheck = true;
return mServiceConfigAccessor.updateConfiguration(
currentUserId, configuration, bypassUserPolicyCheck);
}
@Override
public boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);
int userId = mCurrentUserIdentityInjector.getCurrentUserId();
return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal, false);
}
@Override
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);

View File

@@ -49,6 +49,7 @@ import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
import com.android.server.timezonedetector.CallerIdentityInjector;
import com.android.server.timezonedetector.CurrentUserIdentityInjector;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -84,8 +85,11 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
// Create and publish the local service for use by internal callers.
TimeDetectorInternal internal =
new TimeDetectorInternalImpl(context, handler, timeDetectorStrategy);
CurrentUserIdentityInjector currentUserIdentityInjector =
CurrentUserIdentityInjector.REAL;
TimeDetectorInternal internal = new TimeDetectorInternalImpl(
context, handler, currentUserIdentityInjector, serviceConfigAccessor,
timeDetectorStrategy);
publishLocalService(TimeDetectorInternal.class, internal);
CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
@@ -147,7 +151,8 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
try {
ConfigurationInternal configurationInternal =
mServiceConfigAccessor.getConfigurationInternal(userId);
return configurationInternal.capabilitiesAndConfig();
final boolean bypassUserPolicyCheck = false;
return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyCheck);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -170,7 +175,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mServiceConfigAccessor.updateConfiguration(resolvedUserId, configuration);
final boolean bypassUserPolicyCheck = false;
return mServiceConfigAccessor.updateConfiguration(
resolvedUserId, configuration, bypassUserPolicyCheck);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -313,7 +320,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal);
final boolean bypassUserPolicyChecks = false;
return mTimeDetectorStrategy.suggestManualTime(
userId, timeSignal, bypassUserPolicyChecks);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -335,7 +344,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal);
final boolean bypassUserPolicyChecks = false;
return mTimeDetectorStrategy.suggestManualTime(
userId, timeSignal, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -400,19 +411,19 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
}
private void enforceSuggestManualTimePermission() {
mContext.enforceCallingOrSelfPermission(
mContext.enforceCallingPermission(
android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE,
"suggest manual time and time zone");
}
private void enforceSuggestNetworkTimePermission() {
mContext.enforceCallingOrSelfPermission(
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME,
"set time");
}
private void enforceSuggestGnssTimePermission() {
mContext.enforceCallingOrSelfPermission(
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME,
"suggest gnss time");
}

View File

@@ -93,8 +93,12 @@ public interface TimeDetectorStrategy extends Dumpable {
* invalid, or the device configuration prevented the suggestion being used, {@code true} if the
* suggestion was accepted. A suggestion that is valid but does not change the time because it
* matches the current device time is considered accepted.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion timeSuggestion);
boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion timeSuggestion,
boolean bypassUserPolicyChecks);
/** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);

View File

@@ -16,6 +16,8 @@
package com.android.server.timedetector;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import static com.android.server.SystemClockTime.TIME_CONFIDENCE_HIGH;
import static com.android.server.SystemClockTime.TIME_CONFIDENCE_LOW;
import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
@@ -26,6 +28,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeCapabilities;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
@@ -244,7 +248,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@Override
public synchronized boolean suggestManualTime(
@UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion) {
@UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion,
boolean bypassUserPolicyChecks) {
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
if (currentUserConfig.getUserId() != userId) {
@@ -256,6 +261,18 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
Objects.requireNonNull(suggestion);
String cause = "Manual time suggestion received: suggestion=" + suggestion;
TimeCapabilitiesAndConfig capabilitiesAndConfig =
currentUserConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
if (capabilities.getSetManualTimeCapability() != CAPABILITY_POSSESSED) {
Slog.i(LOG_TAG, "User does not have the capability needed to set the time manually"
+ ": capabilities=" + capabilities
+ ", suggestion=" + suggestion
+ ", cause=" + cause);
return false;
}
final UnixEpochTime newUnixEpochTime = suggestion.getUnixEpochTime();
@@ -263,7 +280,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
return false;
}
String cause = "Manual time suggestion received: suggestion=" + suggestion;
return setSystemClockAndConfidenceIfRequired(ORIGIN_MANUAL, newUnixEpochTime, cause);
}
@@ -428,7 +444,10 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
ipw.println("mCurrentConfigurationInternal=" + mCurrentConfigurationInternal);
ipw.println("[Capabilities=" + mCurrentConfigurationInternal.capabilitiesAndConfig() + "]");
final boolean bypassUserPolicyChecks = false;
ipw.println("[Capabilities="
+ mCurrentConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks)
+ "]");
long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
ipw.printf("mEnvironment.elapsedRealtimeMillis()=%s (%s)\n",
Duration.ofMillis(elapsedRealtimeMillis), elapsedRealtimeMillis);

View File

@@ -147,7 +147,13 @@ public final class ConfigurationInternal {
return UserHandle.of(mUserId);
}
/** Returns true if the user allowed to modify time zone configuration. */
/**
* Returns true if the user is allowed to modify time zone configuration, e.g. can be false due
* to device policy (enterprise).
*
* <p>See also {@link #createCapabilitiesAndConfig(boolean)} for situations where this value
* are ignored.
*/
public boolean isUserConfigAllowed() {
return mUserConfigAllowed;
}
@@ -190,17 +196,24 @@ public final class ConfigurationInternal {
|| getGeoDetectionRunInBackgroundEnabled());
}
/** Creates a {@link TimeZoneCapabilitiesAndConfig} object using the configuration values. */
public TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig() {
return new TimeZoneCapabilitiesAndConfig(asCapabilities(), asConfiguration());
/**
* Creates a {@link TimeZoneCapabilitiesAndConfig} object using the configuration values.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
public TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig(
boolean bypassUserPolicyChecks) {
return new TimeZoneCapabilitiesAndConfig(
asCapabilities(bypassUserPolicyChecks), asConfiguration());
}
@NonNull
private TimeZoneCapabilities asCapabilities() {
private TimeZoneCapabilities asCapabilities(boolean bypassUserPolicyChecks) {
UserHandle userHandle = UserHandle.of(mUserId);
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userHandle);
boolean allowConfigDateTime = isUserConfigAllowed();
boolean allowConfigDateTime = isUserConfigAllowed() || bypassUserPolicyChecks;
// Automatic time zone detection is only supported on devices if there is a telephony
// network available or geolocation time zone detection is possible.

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2022 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 com.android.server.timezonedetector;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import com.android.server.LocalServices;
/**
* An interface to access the current user identity in an easy to fake for tests way.
*/
public interface CurrentUserIdentityInjector {
/** A singleton for the real implementation of {@link CurrentUserIdentityInjector}. */
CurrentUserIdentityInjector REAL = new Real();
/** A {@link ActivityManagerInternal#getCurrentUserId()} call. */
@UserIdInt int getCurrentUserId();
/** The real implementation of {@link CurrentUserIdentityInjector}. */
class Real implements CurrentUserIdentityInjector {
protected Real() {
}
@Override
public int getCurrentUserId() {
return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
}
}
}

View File

@@ -81,11 +81,15 @@ public interface ServiceConfigAccessor {
/**
* Updates the configuration properties that control a device's time zone behavior.
*
* <p>This method returns {@code true} if the configuration was changed,
* {@code false} otherwise.
* <p>This method returns {@code true} if the configuration was changed, {@code false}
* otherwise.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
boolean updateConfiguration(@UserIdInt int userId,
@NonNull TimeZoneConfiguration requestedConfiguration);
boolean updateConfiguration(
@UserIdInt int userId, @NonNull TimeZoneConfiguration requestedConfiguration,
boolean bypassUserPolicyChecks);
/**
* Returns a snapshot of the configuration that controls time zone detector behavior for the

View File

@@ -234,11 +234,11 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
@Override
public synchronized boolean updateConfiguration(@UserIdInt int userId,
@NonNull TimeZoneConfiguration requestedConfiguration) {
@NonNull TimeZoneConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) {
Objects.requireNonNull(requestedConfiguration);
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
getConfigurationInternal(userId).createCapabilitiesAndConfig();
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = getConfigurationInternal(userId)
.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeZoneConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();

View File

@@ -17,16 +17,47 @@
package com.android.server.timezonedetector;
import android.annotation.NonNull;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
/**
* The internal (in-process) system server API for the {@link
* com.android.server.timezonedetector.TimeZoneDetectorService}.
* The internal (in-process) system server API for the time zone detector service.
*
* <p>The methods on this class can be called from any thread.
*
* <p>Methods marked with "[For device policy manager only]" are for use by the device policy
* manager to set device state and must not enforce device policy restrictions.
*
* @hide
*/
public interface TimeZoneDetectorInternal {
/**
* [For device policy manager only] Returns a snapshot of the configuration that controls time
* zone detector behavior for the current user.
*/
@NonNull
TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfigForDpm();
/**
* [For device policy manager only] Updates the configuration properties that control a device's
* time zone behavior for the current user.
*
* <p>This method returns {@code true} if the configuration was changed,
* {@code false} otherwise.
*/
boolean updateConfigurationForDpm(@NonNull TimeZoneConfiguration configuration);
/**
* [For device policy manager only] Attempts to set the device to a manually entered time zone.
* Returns {@code false} if the suggestion is invalid, or the device configuration prevents the
* suggestion being used, {@code true} if the suggestion has been accepted. A suggestion that is
* valid but does not change the time zone because it matches the current device time zone is
* considered accepted.
*/
boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion);
/**
* Suggests the current time zone, determined using geolocation, to the detector. The
* detector may ignore the signal based on system settings, whether better information is

View File

@@ -17,6 +17,9 @@
package com.android.server.timezonedetector;
import android.annotation.NonNull;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.content.Context;
import android.os.Handler;
@@ -31,15 +34,51 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
@NonNull private final CurrentUserIdentityInjector mCurrentUserIdentityInjector;
@NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull CurrentUserIdentityInjector currentUserIdentityInjector,
@NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mCurrentUserIdentityInjector = Objects.requireNonNull(currentUserIdentityInjector);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
}
@Override
@NonNull
public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfigForDpm() {
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
ConfigurationInternal configurationInternal =
mServiceConfigAccessor.getConfigurationInternal(currentUserId);
final boolean bypassUserPolicyChecks = true;
return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
}
@Override
public boolean updateConfigurationForDpm(@NonNull TimeZoneConfiguration configuration) {
Objects.requireNonNull(configuration);
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyChecks = true;
return mServiceConfigAccessor.updateConfiguration(
currentUserId, configuration, bypassUserPolicyChecks);
}
@Override
public boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
Objects.requireNonNull(timeZoneSuggestion);
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyChecks = true;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
currentUserId, timeZoneSuggestion, bypassUserPolicyChecks);
}
@Override
public void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {

View File

@@ -96,8 +96,11 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
});
// Create and publish the local service for use by internal callers.
TimeZoneDetectorInternal internal =
new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
CurrentUserIdentityInjector currentUserIdentityInjector =
CurrentUserIdentityInjector.REAL;
TimeZoneDetectorInternal internal = new TimeZoneDetectorInternalImpl(
context, handler, currentUserIdentityInjector, serviceConfigAccessor,
timeZoneDetectorStrategy);
publishLocalService(TimeZoneDetectorInternal.class, internal);
// Publish the binder service so it can be accessed from other (appropriately
@@ -175,7 +178,8 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
try {
ConfigurationInternal configurationInternal =
mServiceConfigAccessor.getConfigurationInternal(userId);
return configurationInternal.createCapabilitiesAndConfig();
final boolean bypassUserPolicyChecks = false;
return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -199,7 +203,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mServiceConfigAccessor.updateConfiguration(resolvedUserId, configuration);
final boolean bypassUserPolicyChecks = false;
return mServiceConfigAccessor.updateConfiguration(
resolvedUserId, configuration, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -350,7 +356,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
userId, timeZoneSuggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -364,7 +372,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
userId, timeZoneSuggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -449,7 +459,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
private void enforceSuggestGeolocationTimeZonePermission() {
// The associated method is only used for the shell command interface, it's not possible to
// call it via Binder, and Shell currently can set the time zone directly anyway.
mContext.enforceCallingOrSelfPermission(
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME_ZONE,
"suggest geolocation time zone");
}
@@ -461,7 +471,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
}
private void enforceSuggestManualTimeZonePermission() {
mContext.enforceCallingOrSelfPermission(
mContext.enforceCallingPermission(
android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE,
"suggest manual time and time zone");
}

View File

@@ -120,9 +120,13 @@ public interface TimeZoneDetectorStrategy extends Dumpable {
/**
* Suggests a time zone for the device using manually-entered (i.e. user sourced) information.
*
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
boolean suggestManualTimeZone(
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion);
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion,
boolean bypassUserPolicyChecks);
/**
* Suggests a time zone for the device, or withdraws a previous suggestion if

View File

@@ -317,7 +317,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@Override
public synchronized boolean suggestManualTimeZone(
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) {
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion,
boolean bypassUserPolicyChecks) {
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
if (currentUserConfig.getUserId() != userId) {
@@ -334,7 +335,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
String cause = "Manual time suggestion received: suggestion=" + suggestion;
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
currentUserConfig.createCapabilitiesAndConfig();
currentUserConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
if (capabilities.getSetManualTimeZoneCapability() != CAPABILITY_POSSESSED) {
Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
@@ -757,7 +758,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
ipw.increaseIndent(); // level 1
ipw.println("mCurrentConfigurationInternal=" + mCurrentConfigurationInternal);
ipw.println("[Capabilities=" + mCurrentConfigurationInternal.createCapabilitiesAndConfig()
final boolean bypassUserPolicyChecks = false;
ipw.println("[Capabilities="
+ mCurrentConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks)
+ "]");
ipw.println("mEnvironment.getDeviceTimeZone()=" + mEnvironment.getDeviceTimeZone());
ipw.println("mEnvironment.getDeviceTimeZoneConfidence()="

View File

@@ -31,8 +31,6 @@ import android.app.time.TimeCapabilities;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import org.junit.Test;
@@ -40,7 +38,14 @@ import org.junit.runner.RunWith;
import java.time.Instant;
@RunWith(AndroidJUnit4.class)
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
/**
* Tests for {@link ConfigurationInternal} and associated {@link TimeCapabilitiesAndConfig}
* behavior.
*/
@RunWith(JUnitParamsRunner.class)
public class ConfigurationInternalTest {
private static final int ARBITRARY_USER_ID = 99999;
@@ -51,116 +56,86 @@ public class ConfigurationInternalTest {
private static final @Origin int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
/**
* Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
* {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
* Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
* is supported.
*/
@Test
public void test_unrestricted() {
ConfigurationInternal
baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
.setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
.setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
.setAutoDetectionEnabledSetting(true)
.build();
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
.build();
assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSetManualTimeCapability());
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertTrue(configuration.isAutoDetectionEnabled());
}
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED,
capabilities.getSetManualTimeCapability());
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertFalse(configuration.isAutoDetectionEnabled());
}
}
/** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
@Test
public void test_restricted() {
ConfigurationInternal
baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(false)
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
.setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
.setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
.setAutoDetectionEnabledSetting(true)
.build();
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
.build();
assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertTrue(configuration.isAutoDetectionEnabled());
}
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertFalse(configuration.isAutoDetectionEnabled());
}
}
/** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
@Test
public void test_autoDetectNotSupported() {
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void test_autoDetectionSupported_capabilitiesAndConfiguration(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setUserConfigAllowed(userConfigAllowed)
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
.setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
.setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
.setAutoDetectionEnabledSetting(true)
.build();
boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
.build();
assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSetManualTimeCapability());
}
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertTrue(configuration.isAutoDetectionEnabled());
}
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED,
capabilities.getSetManualTimeCapability());
}
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertFalse(configuration.isAutoDetectionEnabled());
}
}
/**
* Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
* is not supported.
*/
@Test
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void test_autoDetectNotSupported_capabilitiesAndConfiguration(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(userConfigAllowed)
.setAutoDetectionSupported(false)
.setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
.setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
@@ -169,6 +144,9 @@ public class ConfigurationInternalTest {
.setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
.setAutoDetectionEnabledSetting(true)
.build();
boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
// Auto-detection enabled.
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
@@ -176,30 +154,41 @@ public class ConfigurationInternalTest {
assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOnConfig.capabilitiesAndConfig();
TimeCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
} else {
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeCapability());
}
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertTrue(configuration.isAutoDetectionEnabled());
}
// Auto-detection disabled.
{
ConfigurationInternal
autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
TimeCapabilitiesAndConfig capabilitiesAndConfig = autoOffConfig.capabilitiesAndConfig();
TimeCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeCapability());
} else {
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeCapability());
}
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertFalse(configuration.isAutoDetectionEnabled());

View File

@@ -31,7 +31,7 @@ import java.util.ArrayList;
import java.util.List;
/** A partially implemented, fake implementation of ServiceConfigAccessor for tests. */
class FakeServiceConfigAccessor implements ServiceConfigAccessor {
public class FakeServiceConfigAccessor implements ServiceConfigAccessor {
private final List<ConfigurationChangeListener> mConfigurationInternalChangeListeners =
new ArrayList<>();
@@ -54,7 +54,8 @@ class FakeServiceConfigAccessor implements ServiceConfigAccessor {
@Override
public boolean updateConfiguration(
@UserIdInt int userID, @NonNull TimeConfiguration requestedChanges) {
@UserIdInt int userID, @NonNull TimeConfiguration requestedChanges,
boolean bypassUserPolicyChecks) {
assertNotNull(mConfigurationInternal);
assertNotNull(requestedChanges);
@@ -62,7 +63,7 @@ class FakeServiceConfigAccessor implements ServiceConfigAccessor {
// old configuration merged with the new if the user has the capability to up the settings.
// Then, if the configuration changed, the change listener is invoked.
TimeCapabilitiesAndConfig capabilitiesAndConfig =
mConfigurationInternal.capabilitiesAndConfig();
mConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
TimeConfiguration newConfiguration =

View File

@@ -16,9 +16,6 @@
package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeState;
@@ -31,20 +28,10 @@ import android.util.IndentingPrintWriter;
* A fake implementation of {@link com.android.server.timedetector.TimeDetectorStrategy} for use
* in tests.
*/
class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
// State
private TimeState mTimeState;
// Call tracking.
private TelephonyTimeSuggestion mLastTelephonySuggestion;
private @UserIdInt Integer mLastManualSuggestionUserId;
private ManualTimeSuggestion mLastManualSuggestion;
private NetworkTimeSuggestion mLastNetworkSuggestion;
private GnssTimeSuggestion mLastGnssSuggestion;
private ExternalTimeSuggestion mLastExternalSuggestion;
private UnixEpochTime mLastConfirmedTime;
private boolean mDumpCalled;
@Override
public TimeState getTimeState() {
return mTimeState;
@@ -57,80 +44,32 @@ class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
@Override
public boolean confirmTime(UnixEpochTime confirmationTime) {
mLastConfirmedTime = confirmationTime;
return false;
}
@Override
public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
mLastTelephonySuggestion = timeSuggestion;
}
@Override
public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion) {
mLastManualSuggestionUserId = userId;
mLastManualSuggestion = timeSuggestion;
public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion,
boolean bypassUserPolicyChecks) {
return true;
}
@Override
public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
mLastNetworkSuggestion = timeSuggestion;
}
@Override
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
mLastGnssSuggestion = timeSuggestion;
}
@Override
public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
mLastExternalSuggestion = timeSuggestion;
}
@Override
public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
void resetCallTracking() {
mLastTelephonySuggestion = null;
mLastManualSuggestionUserId = null;
mLastManualSuggestion = null;
mLastNetworkSuggestion = null;
mLastGnssSuggestion = null;
mLastExternalSuggestion = null;
mLastConfirmedTime = null;
mDumpCalled = false;
}
void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
void verifySuggestManualTimeCalled(
@UserIdInt int expectedUserId, ManualTimeSuggestion expectedSuggestion) {
assertEquals((Integer) expectedUserId, mLastManualSuggestionUserId);
assertEquals(expectedSuggestion, mLastManualSuggestion);
}
void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastNetworkSuggestion);
}
void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastGnssSuggestion);
}
void verifySuggestExternalTimeCalled(ExternalTimeSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastExternalSuggestion);
}
void verifyConfirmTimeCalled(UnixEpochTime expectedConfirmationTime) {
assertEquals(mLastConfirmedTime, expectedConfirmationTime);
}
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
}

View File

@@ -16,14 +16,24 @@
package com.android.server.timedetector;
import static org.mockito.Mockito.mock;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
import android.content.Context;
import android.os.HandlerThread;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.timezonedetector.TestCurrentUserIdentityInjector;
import com.android.server.timezonedetector.TestHandler;
import org.junit.After;
@@ -31,15 +41,25 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Instant;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorInternalImplTest {
private static final int ARBITRARY_USER_ID = 9999;
private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234;
private static final Instant ARBITRARY_SUGGESTION_LOWER_BOUND = Instant.ofEpochMilli(0);
private static final Instant ARBITRARY_SUGGESTION_UPPER_BOUND =
Instant.ofEpochMilli(Long.MAX_VALUE);
private static final int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK };
private Context mMockContext;
private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
private TimeDetectorInternalImpl mTimeDetectorInternal;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TestCurrentUserIdentityInjector mTestCurrentUserIdentityInjector;
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeTimeDetectorStrategy mFakeTimeDetectorStrategySpy;
private TimeDetectorInternalImpl mTimeDetectorInternal;
@Before
public void setUp() {
@@ -49,11 +69,14 @@ public class TimeDetectorInternalImplTest {
mHandlerThread = new HandlerThread("TimeDetectorInternalTest");
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
mTestCurrentUserIdentityInjector = new TestCurrentUserIdentityInjector();
mTestCurrentUserIdentityInjector.initializeCurrentUserId(ARBITRARY_USER_ID);
mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
mFakeTimeDetectorStrategySpy = spy(new FakeTimeDetectorStrategy());
mTimeDetectorInternal = new TimeDetectorInternalImpl(
mMockContext, mTestHandler, mFakeTimeDetectorStrategy);
mMockContext, mTestHandler, mTestCurrentUserIdentityInjector,
mFakeServiceConfigAccessorSpy, mFakeTimeDetectorStrategySpy);
}
@After
@@ -62,6 +85,56 @@ public class TimeDetectorInternalImplTest {
mHandlerThread.join();
}
@Test
public void testGetCapabilitiesAndConfigForDpm() throws Exception {
final boolean autoDetectionEnabled = true;
ConfigurationInternal testConfig = createConfigurationInternal(autoDetectionEnabled);
mFakeServiceConfigAccessorSpy.initializeConfiguration(testConfig);
TimeCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeDetectorInternal.getCapabilitiesAndConfigForDpm();
int expectedUserId = mTestCurrentUserIdentityInjector.getCurrentUserId();
verify(mFakeServiceConfigAccessorSpy).getConfigurationInternal(expectedUserId);
final boolean bypassUserPolicyChecks = true;
TimeCapabilitiesAndConfig expectedCapabilitiesAndConfig =
testConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
}
@Test
public void testUpdateConfigurationForDpm() throws Exception {
final boolean autoDetectionEnabled = false;
ConfigurationInternal initialConfigurationInternal =
createConfigurationInternal(autoDetectionEnabled);
mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfigurationInternal);
TimeConfiguration timeConfiguration = new TimeConfiguration.Builder()
.setAutoDetectionEnabled(true)
.build();
assertTrue(mTimeDetectorInternal.updateConfigurationForDpm(timeConfiguration));
final boolean expectedBypassUserPolicyChecks = true;
verify(mFakeServiceConfigAccessorSpy).updateConfiguration(
mTestCurrentUserIdentityInjector.getCurrentUserId(),
timeConfiguration,
expectedBypassUserPolicyChecks);
}
@Test
public void testSetManualTimeZoneForDpm() throws Exception {
ManualTimeSuggestion timeSuggestion = createManualTimeSuggestion();
// The fake strategy always returns true.
assertTrue(mTimeDetectorInternal.setManualTimeForDpm(timeSuggestion));
int expectedUserId = mTestCurrentUserIdentityInjector.getCurrentUserId();
boolean expectedBypassUserPolicyChecks = false;
verify(mFakeTimeDetectorStrategySpy).suggestManualTime(
expectedUserId, timeSuggestion, expectedBypassUserPolicyChecks);
}
@Test
public void testSuggestNetworkTime() throws Exception {
NetworkTimeSuggestion networkTimeSuggestion = createNetworkTimeSuggestion();
@@ -70,7 +143,7 @@ public class TimeDetectorInternalImplTest {
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestNetworkTimeCalled(networkTimeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestNetworkTime(networkTimeSuggestion);
}
private static NetworkTimeSuggestion createNetworkTimeSuggestion() {
@@ -86,11 +159,29 @@ public class TimeDetectorInternalImplTest {
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestGnssTime(gnssTimeSuggestion);
}
private static ManualTimeSuggestion createManualTimeSuggestion() {
UnixEpochTime timeValue = new UnixEpochTime(100L, 1_000_000L);
return new ManualTimeSuggestion(timeValue);
}
private static GnssTimeSuggestion createGnssTimeSuggestion() {
UnixEpochTime timeValue = new UnixEpochTime(100L, 1_000_000L);
return new GnssTimeSuggestion(timeValue);
}
private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
.setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND)
.setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES)
.setAutoDetectionEnabledSetting(autoDetectionEnabled)
.build();
}
}

View File

@@ -31,12 +31,14 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.ITimeDetectorListener;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
@@ -77,14 +79,14 @@ public class TimeDetectorServiceTest {
private Context mMockContext;
private TimeDetectorService mTimeDetectorService;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TestCallerIdentityInjector mTestCallerIdentityInjector;
private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
private NtpTrustedTime mMockNtpTrustedTime;
private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeTimeDetectorStrategy mFakeTimeDetectorStrategySpy;
private NtpTrustedTime mMockNtpTrustedTime;
private TimeDetectorService mTimeDetectorService;
@Before
public void setUp() {
@@ -98,13 +100,13 @@ public class TimeDetectorServiceTest {
mTestCallerIdentityInjector = new TestCallerIdentityInjector();
mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
mFakeTimeDetectorStrategySpy = spy(new FakeTimeDetectorStrategy());
mMockNtpTrustedTime = mock(NtpTrustedTime.class);
mTimeDetectorService = new TimeDetectorService(
mMockContext, mTestHandler, mTestCallerIdentityInjector, mFakeServiceConfigAccessor,
mFakeTimeDetectorStrategy, mMockNtpTrustedTime);
mMockContext, mTestHandler, mTestCallerIdentityInjector,
mFakeServiceConfigAccessorSpy, mFakeTimeDetectorStrategySpy, mMockNtpTrustedTime);
}
@After
@@ -129,13 +131,19 @@ public class TimeDetectorServiceTest {
ConfigurationInternal configuration =
createConfigurationInternal(true /* autoDetectionEnabled*/);
mFakeServiceConfigAccessor.initializeConfiguration(configuration);
assertEquals(configuration.capabilitiesAndConfig(),
mTimeDetectorService.getCapabilitiesAndConfig());
mFakeServiceConfigAccessorSpy.initializeConfiguration(configuration);
TimeCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeDetectorService.getCapabilitiesAndConfig();
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
verify(mFakeServiceConfigAccessorSpy).getConfigurationInternal(expectedUserId);
boolean bypassUserPolicyChecks = false;
TimeCapabilitiesAndConfig expectedCapabilitiesAndConfig =
configuration.createCapabilitiesAndConfig(bypassUserPolicyChecks);
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
}
@Test
@@ -165,7 +173,7 @@ public class TimeDetectorServiceTest {
public void testListenerRegistrationAndCallbacks() throws Exception {
ConfigurationInternal initialConfiguration =
createConfigurationInternal(false /* autoDetectionEnabled */);
mFakeServiceConfigAccessor.initializeConfiguration(initialConfiguration);
mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeDetectorListener mockListener = mock(ITimeDetectorListener.class);
@@ -258,32 +266,34 @@ public class TimeDetectorServiceTest {
eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestTelephonyTime(timeSuggestion);
}
@Test
public void testSuggestManualTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
.when(mMockContext).enforceCallingPermission(anyString(), any());
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
assertThrows(SecurityException.class,
() -> mTimeDetectorService.suggestManualTime(manualTimeSuggestion));
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), anyString());
}
@Test
public void testSuggestManualTime() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
assertTrue(mTimeDetectorService.suggestManualTime(manualTimeSuggestion));
mFakeTimeDetectorStrategy.verifySuggestManualTimeCalled(
mTestCallerIdentityInjector.getCallingUserId(), manualTimeSuggestion);
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
boolean expectedBypassUserPolicyChecks = false;
verify(mFakeTimeDetectorStrategySpy).suggestManualTime(
expectedUserId, manualTimeSuggestion, expectedBypassUserPolicyChecks);
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), anyString());
}
@@ -291,55 +301,55 @@ public class TimeDetectorServiceTest {
@Test
public void testSuggestNetworkTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
.when(mMockContext).enforceCallingPermission(anyString(), any());
NetworkTimeSuggestion networkTimeSuggestion = createNetworkTimeSuggestion();
assertThrows(SecurityException.class,
() -> mTimeDetectorService.suggestNetworkTime(networkTimeSuggestion));
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
}
@Test
public void testSuggestNetworkTime() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
NetworkTimeSuggestion networkTimeSuggestion = createNetworkTimeSuggestion();
mTimeDetectorService.suggestNetworkTime(networkTimeSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestNetworkTimeCalled(networkTimeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestNetworkTime(networkTimeSuggestion);
}
@Test
public void testSuggestGnssTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
.when(mMockContext).enforceCallingPermission(anyString(), any());
GnssTimeSuggestion gnssTimeSuggestion = createGnssTimeSuggestion();
assertThrows(SecurityException.class,
() -> mTimeDetectorService.suggestGnssTime(gnssTimeSuggestion));
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
}
@Test
public void testSuggestGnssTime() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
GnssTimeSuggestion gnssTimeSuggestion = createGnssTimeSuggestion();
mTimeDetectorService.suggestGnssTime(gnssTimeSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestGnssTime(gnssTimeSuggestion);
}
@Test
@@ -366,7 +376,7 @@ public class TimeDetectorServiceTest {
eq(android.Manifest.permission.SUGGEST_EXTERNAL_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeDetectorStrategy.verifySuggestExternalTimeCalled(externalTimeSuggestion);
verify(mFakeTimeDetectorStrategySpy).suggestExternalTime(externalTimeSuggestion);
}
@Test
@@ -390,7 +400,7 @@ public class TimeDetectorServiceTest {
public void testGetTimeState() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
TimeState fakeState = new TimeState(new UnixEpochTime(12345L, 98765L), true);
mFakeTimeDetectorStrategy.setTimeState(fakeState);
mFakeTimeDetectorStrategySpy.setTimeState(fakeState);
TimeState actualState = mTimeDetectorService.getTimeState();
@@ -418,7 +428,7 @@ public class TimeDetectorServiceTest {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
assertEquals(mFakeTimeDetectorStrategy.getTimeState(), state);
assertEquals(mFakeTimeDetectorStrategySpy.getTimeState(), state);
}
@Test
@@ -442,7 +452,7 @@ public class TimeDetectorServiceTest {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
mFakeTimeDetectorStrategy.verifyConfirmTimeCalled(confirmationTime);
verify(mFakeTimeDetectorStrategySpy).confirmTime(confirmationTime);
}
@Test
@@ -467,8 +477,10 @@ public class TimeDetectorServiceTest {
mTimeDetectorService.setManualTime(timeSuggestion));
// The service calls "suggestManualTime()" because the logic is the same.
mFakeTimeDetectorStrategy.verifySuggestManualTimeCalled(
mTestCallerIdentityInjector.getCallingUserId(), timeSuggestion);
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
boolean expectedBypassUserPolicyChecks = false;
verify(mFakeTimeDetectorStrategySpy).suggestManualTime(
expectedUserId, timeSuggestion, expectedBypassUserPolicyChecks);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
@@ -495,7 +507,7 @@ public class TimeDetectorServiceTest {
mTimeDetectorService.dump(null, pw, null);
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
mFakeTimeDetectorStrategy.verifyDumpCalled();
verify(mFakeTimeDetectorStrategySpy).dump(any(), any());
}
private static TimeConfiguration createTimeConfiguration(boolean autoDetectionEnabled) {

View File

@@ -38,8 +38,6 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.server.timezonedetector.ConfigurationChangeListener;
@@ -55,7 +53,10 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;
@RunWith(AndroidJUnit4.class)
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
@RunWith(JUnitParamsRunner.class)
public class TimeDetectorStrategyImplTest {
private static final @UserIdInt int ARBITRARY_USER_ID = 9876;
@@ -656,12 +657,45 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
/** Confirms the effect of user policy restrictions on being able to set the time. */
@Test
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void testSuggestManualTime_autoTimeDisabled_userRestrictions(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal configAutoDisabled =
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setUserConfigAllowed(userConfigAllowed)
.build();
Script script = new Script().simulateConfigurationInternalChange(configAutoDisabled)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
ManualTimeSuggestion timeSuggestion =
script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
script.simulateTimePassing();
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
boolean expectedResult = userConfigAllowed || bypassUserPolicyChecks;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult);
if (expectedResult) {
script.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
} else {
script.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
}
@Test
public void testSuggestManualTime_retainsAutoSignal() {
Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
@@ -704,8 +738,10 @@ public class TimeDetectorStrategyImplTest {
long expectedManualClockMillis =
script.calculateTimeInMillisForNow(manualTimeSuggestion.getUnixEpochTime());
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, manualTimeSuggestion, true /* expectedResult */)
ARBITRARY_USER_ID, manualTimeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -737,9 +773,10 @@ public class TimeDetectorStrategyImplTest {
ManualTimeSuggestion timeSuggestion =
script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
script.simulateTimePassing()
.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
boolean bypassUserPolicyChecks = false;
boolean expectedResult = false;
script.simulateTimePassing().simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -755,8 +792,10 @@ public class TimeDetectorStrategyImplTest {
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveUpperBound);
boolean bypassUserPolicyChecks = false;
boolean expectedResult = false;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -772,8 +811,10 @@ public class TimeDetectorStrategyImplTest {
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowUpperBound);
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -789,8 +830,10 @@ public class TimeDetectorStrategyImplTest {
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowLowerBound);
boolean bypassUserPolicyChecks = false;
boolean expectedResult = false;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -806,8 +849,10 @@ public class TimeDetectorStrategyImplTest {
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveLowerBound);
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -1758,8 +1803,10 @@ public class TimeDetectorStrategyImplTest {
ManualTimeSuggestion timeSuggestion =
script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
ARBITRARY_USER_ID, timeSuggestion, bypassUserPolicyChecks, expectedResult)
.verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
}
@@ -1951,14 +1998,15 @@ public class TimeDetectorStrategyImplTest {
Script simulateManualTimeSuggestion(
@UserIdInt int userId, ManualTimeSuggestion timeSuggestion,
boolean expectedResult) {
boolean bypassUserPolicyChecks, boolean expectedResult) {
String errorMessage = expectedResult
? "Manual time suggestion was ignored, but expected to be accepted."
: "Manual time suggestion was accepted, but expected to be ignored.";
assertEquals(
errorMessage,
expectedResult,
mTimeDetectorStrategy.suggestManualTime(userId, timeSuggestion));
mTimeDetectorStrategy.suggestManualTime(
userId, timeSuggestion, bypassUserPolicyChecks));
return this;
}

View File

@@ -29,27 +29,36 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeZoneCapabilities;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
/**
* Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilitiesAndConfig}.
* Tests for {@link ConfigurationInternal} and associated {@link TimeZoneCapabilitiesAndConfig}
* behavior.
*/
@RunWith(JUnitParamsRunner.class)
public class ConfigurationInternalTest {
private static final int ARBITRARY_USER_ID = 99999;
/**
* Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
* {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
* Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
* is supported (and geo detection is supported)
*/
@Test
public void test_unrestricted() {
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void test_autoDetectionSupported_capabilitiesAndConfiguration(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setUserConfigAllowed(userConfigAllowed)
.setTelephonyDetectionFeatureSupported(true)
.setGeoDetectionFeatureSupported(true)
.setGeoDetectionRunInBackgroundEnabled(false)
@@ -59,6 +68,10 @@ public class ConfigurationInternalTest {
.setLocationEnabledSetting(true)
.setGeoDetectionEnabledSetting(true)
.build();
boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
// Auto-detection enabled.
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
@@ -70,13 +83,21 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_GEO, autoOnConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig();
autoOnConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getSetManualTimeZoneCapability());
}
// This has user privacy implications so it is not restricted in the same way as others.
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureGeoDetectionEnabledCapability());
@@ -85,6 +106,7 @@ public class ConfigurationInternalTest {
assertTrue(configuration.isGeoDetectionEnabled());
}
// Auto-detection disabled.
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
@@ -96,81 +118,20 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig();
autoOffConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED,
capabilities.getSetManualTimeZoneCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getConfigureGeoDetectionEnabledCapability());
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertFalse(configuration.isAutoDetectionEnabled());
assertTrue(configuration.isGeoDetectionEnabled());
}
}
/** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
@Test
public void test_restricted() {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(false)
.setTelephonyDetectionFeatureSupported(true)
.setGeoDetectionFeatureSupported(true)
.setTelephonyFallbackSupported(false)
.setGeoDetectionRunInBackgroundEnabled(false)
.setEnhancedMetricsCollectionEnabled(false)
.setAutoDetectionEnabledSetting(true)
.setLocationEnabledSetting(true)
.setGeoDetectionEnabledSetting(true)
.build();
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
.build();
assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
assertTrue(autoOnConfig.isGeoDetectionExecutionEnabled());
assertEquals(DETECTION_MODE_GEO, autoOnConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig();
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getSetManualTimeZoneCapability());
// This has user privacy implications so it is not restricted in the same way as others.
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureGeoDetectionEnabledCapability());
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
assertTrue(configuration.isAutoDetectionEnabled());
assertTrue(configuration.isGeoDetectionEnabled());
}
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
assertFalse(autoOffConfig.isGeoDetectionExecutionEnabled());
assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig();
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED,
capabilities.getSetManualTimeZoneCapability());
}
// This has user privacy implications so it is not restricted in the same way as others.
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getConfigureGeoDetectionEnabledCapability());
@@ -181,11 +142,16 @@ public class ConfigurationInternalTest {
}
}
/** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
/**
* Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
* is not supported.
*/
@Test
public void test_autoDetectNotSupported() {
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void test_autoDetectNotSupported_capabilitiesAndConfiguration(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setUserConfigAllowed(userConfigAllowed)
.setTelephonyDetectionFeatureSupported(false)
.setGeoDetectionFeatureSupported(false)
.setGeoDetectionRunInBackgroundEnabled(false)
@@ -195,6 +161,10 @@ public class ConfigurationInternalTest {
.setLocationEnabledSetting(true)
.setGeoDetectionEnabledSetting(true)
.build();
boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
// Auto-detection enabled.
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
@@ -206,12 +176,16 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_MANUAL, autoOnConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig();
autoOnConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
}
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureGeoDetectionEnabledCapability());
@@ -219,6 +193,8 @@ public class ConfigurationInternalTest {
assertTrue(configuration.isAutoDetectionEnabled());
assertTrue(configuration.isGeoDetectionEnabled());
}
// Auto-detection disabled.
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
@@ -230,12 +206,16 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig();
autoOffConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
}
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureGeoDetectionEnabledCapability());
@@ -246,13 +226,15 @@ public class ConfigurationInternalTest {
}
/**
* Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is true, but
* {@link ConfigurationInternal#isGeoDetectionSupported()} is false.
* Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
* is supported (and geo detection is not supported).
*/
@Test
public void test_geoDetectNotSupported() {
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void test_geoDetectNotSupported_capabilitiesAndConfiguration(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
.setUserConfigAllowed(userConfigAllowed)
.setTelephonyDetectionFeatureSupported(true)
.setGeoDetectionFeatureSupported(false)
.setGeoDetectionRunInBackgroundEnabled(false)
@@ -262,6 +244,10 @@ public class ConfigurationInternalTest {
.setLocationEnabledSetting(true)
.setGeoDetectionEnabledSetting(true)
.build();
boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
// Auto-detection enabled.
{
ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(true)
@@ -273,13 +259,20 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_TELEPHONY, autoOnConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOnConfig.createCapabilitiesAndConfig();
autoOnConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_APPLICABLE,
capabilities.getSetManualTimeZoneCapability());
}
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureGeoDetectionEnabledCapability());
@@ -287,6 +280,8 @@ public class ConfigurationInternalTest {
assertTrue(configuration.isAutoDetectionEnabled());
assertTrue(configuration.isGeoDetectionEnabled());
}
// Auto-detection disabled.
{
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
.setAutoDetectionEnabledSetting(false)
@@ -298,12 +293,18 @@ public class ConfigurationInternalTest {
assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
autoOffConfig.createCapabilitiesAndConfig();
autoOffConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
if (userRestrictionsExpected) {
assertEquals(CAPABILITY_NOT_ALLOWED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeZoneCapability());
} else {
assertEquals(CAPABILITY_POSSESSED,
capabilities.getConfigureAutoDetectionEnabledCapability());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
}
assertEquals(CAPABILITY_NOT_SUPPORTED,
capabilities.getConfigureGeoDetectionEnabledCapability());

View File

@@ -32,7 +32,7 @@ import java.util.List;
import java.util.Optional;
/** A partially implemented, fake implementation of ServiceConfigAccessor for tests. */
class FakeServiceConfigAccessor implements ServiceConfigAccessor {
public class FakeServiceConfigAccessor implements ServiceConfigAccessor {
private final List<ConfigurationChangeListener> mConfigurationInternalChangeListeners =
new ArrayList<>();
@@ -55,7 +55,8 @@ class FakeServiceConfigAccessor implements ServiceConfigAccessor {
@Override
public boolean updateConfiguration(
@UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges) {
@UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges,
boolean bypassUserPolicyChecks) {
assertNotNull(mConfigurationInternal);
assertNotNull(requestedChanges);
@@ -63,7 +64,7 @@ class FakeServiceConfigAccessor implements ServiceConfigAccessor {
// old configuration merged with the new if the user has the capability to up the settings.
// Then, if the configuration changed, the change listener is invoked.
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
mConfigurationInternal.createCapabilitiesAndConfig();
mConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
TimeZoneConfiguration newConfiguration =

View File

@@ -15,9 +15,6 @@
*/
package com.android.server.timezonedetector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.time.TimeZoneState;
@@ -25,21 +22,12 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.util.IndentingPrintWriter;
class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
private TimeZoneState mTimeZoneState;
// Call tracking.
private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion;
private ManualTimeZoneSuggestion mLastManualSuggestion;
private Integer mLastManualSuggestionUserId;
private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
private String mLastConfirmedTimeZone;
private boolean mDumpCalled;
@Override
public boolean confirmTimeZone(String timeZoneId) {
mLastConfirmedTimeZone = timeZoneId;
return false;
}
@@ -55,21 +43,17 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
@Override
public void suggestGeolocationTimeZone(GeolocationTimeZoneSuggestion timeZoneSuggestion) {
mLastGeolocationSuggestion = timeZoneSuggestion;
}
@Override
public boolean suggestManualTimeZone(
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
mLastManualSuggestionUserId = userId;
mLastManualSuggestion = timeZoneSuggestion;
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion timeZoneSuggestion,
boolean bypassUserPolicyChecks) {
return true;
}
@Override
public void suggestTelephonyTimeZone(
@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
mLastTelephonySuggestion = timeZoneSuggestion;
public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
}
@Override
@@ -94,38 +78,5 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
@Override
public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
void resetCallTracking() {
mLastGeolocationSuggestion = null;
mLastManualSuggestion = null;
mLastManualSuggestionUserId = null;
mLastTelephonySuggestion = null;
mDumpCalled = false;
mLastConfirmedTimeZone = null;
}
void verifySuggestGeolocationTimeZoneCalled(
GeolocationTimeZoneSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastGeolocationSuggestion);
}
void verifySuggestManualTimeZoneCalled(
@UserIdInt int expectedUserId, ManualTimeZoneSuggestion expectedSuggestion) {
assertEquals((Integer) expectedUserId, mLastManualSuggestionUserId);
assertEquals(expectedSuggestion, mLastManualSuggestion);
}
void verifySuggestTelephonyTimeZoneCalled(TelephonyTimeZoneSuggestion expectedSuggestion) {
assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
void verifyConfirmTimeZoneCalled(String expectedTimeZoneId) {
assertEquals(expectedTimeZoneId, mLastConfirmedTimeZone);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2022 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 com.android.server.timezonedetector;
import android.annotation.UserIdInt;
/** A fake {@link CurrentUserIdentityInjector} used in tests. */
public class TestCurrentUserIdentityInjector implements CurrentUserIdentityInjector {
private Integer mCurrentUserId;
public void initializeCurrentUserId(@UserIdInt int userId) {
mCurrentUserId = userId;
}
@Override
public int getCurrentUserId() {
return mCurrentUserId;
}
}

View File

@@ -16,8 +16,15 @@
package com.android.server.timezonedetector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.content.Context;
import android.os.HandlerThread;
@@ -35,15 +42,18 @@ import java.util.List;
public class TimeZoneDetectorInternalImplTest {
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
private static final List<String> ARBITRARY_ZONE_IDS = Arrays.asList("TestZoneId");
private static final String ARBITRARY_ZONE_ID = "TestZoneId";
private static final List<String> ARBITRARY_ZONE_IDS = Arrays.asList(ARBITRARY_ZONE_ID);
private static final int ARBITRARY_USER_ID = 9999;
private Context mMockContext;
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
private TimeZoneDetectorInternalImpl mTimeZoneDetectorInternal;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TestCurrentUserIdentityInjector mTestCurrentUserIdentityInjector;
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategySpy;
private TimeZoneDetectorInternalImpl mTimeZoneDetectorInternal;
@Before
public void setUp() {
@@ -53,11 +63,14 @@ public class TimeZoneDetectorInternalImplTest {
mHandlerThread = new HandlerThread("TimeZoneDetectorInternalTest");
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mTestCurrentUserIdentityInjector = new TestCurrentUserIdentityInjector();
mTestCurrentUserIdentityInjector.initializeCurrentUserId(ARBITRARY_USER_ID);
mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
mFakeTimeZoneDetectorStrategySpy = spy(new FakeTimeZoneDetectorStrategy());
mTimeZoneDetectorInternal = new TimeZoneDetectorInternalImpl(
mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
mMockContext, mTestHandler, mTestCurrentUserIdentityInjector,
mFakeServiceConfigAccessorSpy, mFakeTimeZoneDetectorStrategySpy);
}
@After
@@ -66,6 +79,56 @@ public class TimeZoneDetectorInternalImplTest {
mHandlerThread.join();
}
@Test
public void testGetCapabilitiesAndConfigForDpm() throws Exception {
final boolean autoDetectionEnabled = true;
ConfigurationInternal testConfig = createConfigurationInternal(autoDetectionEnabled);
mFakeServiceConfigAccessorSpy.initializeConfiguration(testConfig);
TimeZoneCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeZoneDetectorInternal.getCapabilitiesAndConfigForDpm();
int expectedUserId = mTestCurrentUserIdentityInjector.getCurrentUserId();
verify(mFakeServiceConfigAccessorSpy).getConfigurationInternal(expectedUserId);
final boolean bypassUserPolicyChecks = true;
TimeZoneCapabilitiesAndConfig expectedCapabilitiesAndConfig =
testConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
}
@Test
public void testUpdateConfigurationForDpm() throws Exception {
final boolean autoDetectionEnabled = false;
ConfigurationInternal initialConfigurationInternal =
createConfigurationInternal(autoDetectionEnabled);
mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfigurationInternal);
TimeZoneConfiguration timeConfiguration = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(true)
.build();
assertTrue(mTimeZoneDetectorInternal.updateConfigurationForDpm(timeConfiguration));
final boolean expectedBypassUserPolicyChecks = true;
verify(mFakeServiceConfigAccessorSpy).updateConfiguration(
mTestCurrentUserIdentityInjector.getCurrentUserId(),
timeConfiguration,
expectedBypassUserPolicyChecks);
}
@Test
public void testSetManualTimeZoneForDpm() throws Exception {
ManualTimeZoneSuggestion timeZoneSuggestion = createManualTimeZoneSuggestion();
// The fake strategy always returns true.
assertTrue(mTimeZoneDetectorInternal.setManualTimeZoneForDpm(timeZoneSuggestion));
int expectedUserId = mTestCurrentUserIdentityInjector.getCurrentUserId();
boolean expectedBypassUserPolicyChecks = true;
verify(mFakeTimeZoneDetectorStrategySpy).suggestManualTimeZone(
expectedUserId, timeZoneSuggestion, expectedBypassUserPolicyChecks);
}
@Test
public void testSuggestGeolocationTimeZone() throws Exception {
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
@@ -73,11 +136,28 @@ public class TimeZoneDetectorInternalImplTest {
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
verify(mFakeTimeZoneDetectorStrategySpy).suggestGeolocationTimeZone(timeZoneSuggestion);
}
private static ManualTimeZoneSuggestion createManualTimeZoneSuggestion() {
return new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID);
}
private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
return GeolocationTimeZoneSuggestion.createCertainSuggestion(
ARBITRARY_ELAPSED_REALTIME_MILLIS, ARBITRARY_ZONE_IDS);
}
private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setTelephonyDetectionFeatureSupported(true)
.setGeoDetectionFeatureSupported(true)
.setTelephonyFallbackSupported(false)
.setGeoDetectionRunInBackgroundEnabled(false)
.setEnhancedMetricsCollectionEnabled(false)
.setUserConfigAllowed(true)
.setAutoDetectionEnabledSetting(autoDetectionEnabled)
.setLocationEnabledSetting(false)
.setGeoDetectionEnabledSetting(false)
.build();
}
}

View File

@@ -28,11 +28,13 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.time.ITimeZoneDetectorListener;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import android.app.time.TimeZoneState;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
@@ -67,8 +69,8 @@ public class TimeZoneDetectorServiceTest {
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TestCallerIdentityInjector mTestCallerIdentityInjector;
private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategySpy;
@Before
@@ -83,12 +85,12 @@ public class TimeZoneDetectorServiceTest {
mTestCallerIdentityInjector = new TestCallerIdentityInjector();
mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
mFakeTimeZoneDetectorStrategySpy = spy(new FakeTimeZoneDetectorStrategy());
mTimeZoneDetectorService = new TimeZoneDetectorService(
mMockContext, mTestHandler, mTestCallerIdentityInjector,
mFakeServiceConfigAccessor, mFakeTimeZoneDetectorStrategy);
mFakeServiceConfigAccessorSpy, mFakeTimeZoneDetectorStrategySpy);
}
@After
@@ -113,13 +115,21 @@ public class TimeZoneDetectorServiceTest {
ConfigurationInternal configuration =
createConfigurationInternal(true /* autoDetectionEnabled*/);
mFakeServiceConfigAccessor.initializeConfiguration(configuration);
mFakeServiceConfigAccessorSpy.initializeConfiguration(configuration);
assertEquals(configuration.createCapabilitiesAndConfig(),
mTimeZoneDetectorService.getCapabilitiesAndConfig());
TimeZoneCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeZoneDetectorService.getCapabilitiesAndConfig();
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
verify(mFakeServiceConfigAccessorSpy).getConfigurationInternal(expectedUserId);
boolean expectedBypassUserPolicyChecks = false;
TimeZoneCapabilitiesAndConfig expectedCapabilitiesAndConfig =
configuration.createCapabilitiesAndConfig(expectedBypassUserPolicyChecks);
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
}
@Test
@@ -150,7 +160,7 @@ public class TimeZoneDetectorServiceTest {
public void testListenerRegistrationAndCallbacks() throws Exception {
ConfigurationInternal initialConfiguration =
createConfigurationInternal(false /* autoDetectionEnabled */);
mFakeServiceConfigAccessor.initializeConfiguration(initialConfiguration);
mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
@@ -222,46 +232,46 @@ public class TimeZoneDetectorServiceTest {
@Test
public void testSuggestGeolocationTimeZone_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
.when(mMockContext).enforceCallingPermission(anyString(), any());
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
assertThrows(SecurityException.class,
() -> mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion));
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME_ZONE), anyString());
}
@Test
public void testSuggestGeolocationTimeZone() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME_ZONE), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
verify(mFakeTimeZoneDetectorStrategySpy).suggestGeolocationTimeZone(timeZoneSuggestion);
}
@Test
public void testSuggestManualTimeZone_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
.when(mMockContext).enforceCallingPermission(anyString(), any());
ManualTimeZoneSuggestion timeZoneSuggestion = createManualTimeZoneSuggestion();
assertThrows(SecurityException.class,
() -> mTimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion));
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), anyString());
}
@Test
public void testSuggestManualTimeZone() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
ManualTimeZoneSuggestion timeZoneSuggestion = createManualTimeZoneSuggestion();
@@ -269,10 +279,12 @@ public class TimeZoneDetectorServiceTest {
assertEquals(expectedResult,
mTimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion));
mFakeTimeZoneDetectorStrategy.verifySuggestManualTimeZoneCalled(
mTestCallerIdentityInjector.getCallingUserId(), timeZoneSuggestion);
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
boolean expectedBypassUserPolicyChecks = false;
verify(mFakeTimeZoneDetectorStrategySpy).suggestManualTimeZone(
expectedUserId, timeZoneSuggestion, expectedBypassUserPolicyChecks);
verify(mMockContext).enforceCallingOrSelfPermission(
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), anyString());
}
@@ -312,20 +324,20 @@ public class TimeZoneDetectorServiceTest {
eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE), anyString());
mTestHandler.waitForMessagesToBeProcessed();
mFakeTimeZoneDetectorStrategy.verifySuggestTelephonyTimeZoneCalled(timeZoneSuggestion);
verify(mFakeTimeZoneDetectorStrategySpy).suggestTelephonyTimeZone(timeZoneSuggestion);
}
@Test
public void testGetTimeZoneState() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
TimeZoneState fakeState = new TimeZoneState("Europe/Narnia", true);
mFakeTimeZoneDetectorStrategy.setTimeZoneState(fakeState);
mFakeTimeZoneDetectorStrategySpy.setTimeZoneState(fakeState);
TimeZoneState actualState = mTimeZoneDetectorService.getTimeZoneState();
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
assertEquals(actualState, fakeState);
assertEquals(fakeState, actualState);
}
@Test
@@ -347,7 +359,7 @@ public class TimeZoneDetectorServiceTest {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
assertEquals(mFakeTimeZoneDetectorStrategy.getTimeZoneState(), state);
assertEquals(state, mFakeTimeZoneDetectorStrategySpy.getTimeZoneState());
}
@Test
@@ -371,7 +383,7 @@ public class TimeZoneDetectorServiceTest {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
mFakeTimeZoneDetectorStrategy.verifyConfirmTimeZoneCalled("Europe/Narnia");
verify(mFakeTimeZoneDetectorStrategySpy).confirmTimeZone("Europe/Narnia");
}
@Test
@@ -396,8 +408,10 @@ public class TimeZoneDetectorServiceTest {
mTimeZoneDetectorService.setManualTimeZone(timeZoneSuggestion));
// The service calls "suggestManualTimeZone()" because the logic is the same.
mFakeTimeZoneDetectorStrategy.verifySuggestManualTimeZoneCalled(
mTestCallerIdentityInjector.getCallingUserId(), timeZoneSuggestion);
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
boolean expectedBypassUserPolicyChecks = false;
verify(mFakeTimeZoneDetectorStrategySpy).suggestManualTimeZone(
expectedUserId, timeZoneSuggestion, expectedBypassUserPolicyChecks);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
@@ -427,7 +441,7 @@ public class TimeZoneDetectorServiceTest {
mTimeZoneDetectorService.dump(null, pw, null);
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
verify(mFakeTimeZoneDetectorStrategySpy).dump(any(), any());
verify(dumpable).dump(any(), any());
}

View File

@@ -53,6 +53,7 @@ import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.Qualifie
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -60,9 +61,13 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
/**
* White-box unit tests for {@link TimeZoneDetectorStrategyImpl}.
*/
@RunWith(JUnitParamsRunner.class)
public class TimeZoneDetectorStrategyImplTest {
private static final @UserIdInt int USER_ID = 9876;
@@ -561,55 +566,10 @@ public class TimeZoneDetectorStrategyImplTest {
.resetConfigurationTracking();
// Auto time zone detection is enabled so the manual suggestion should be ignored.
script.simulateManualTimeZoneSuggestion(
USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */)
.verifyTimeZoneNotChanged();
assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
@Test
public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(CONFIG_USER_RESTRICTED_AUTO_ENABLED)
.resetConfigurationTracking();
// User is restricted so the manual suggestion should be ignored.
script.simulateManualTimeZoneSuggestion(
USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */)
.verifyTimeZoneNotChanged();
assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
@Test
public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
.resetConfigurationTracking();
// Auto time zone detection is disabled so the manual suggestion should be used.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(manualSuggestion);
assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
@Test
public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(CONFIG_USER_RESTRICTED_AUTO_DISABLED)
.resetConfigurationTracking();
// Restricted users do not have the capability.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, false /* expectedResult */)
boolean bypassUserPolicyChecks = false;
boolean expectedResult = false;
script.simulateManualTimeZoneSuggestion(USER_ID, createManualSuggestion("Europe/Paris"),
bypassUserPolicyChecks, expectedResult)
.verifyTimeZoneNotChanged();
assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion());
@@ -624,13 +584,63 @@ public class TimeZoneDetectorStrategyImplTest {
// Unrestricted users have the capability.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, true /* expectedResult */)
USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult)
.verifyTimeZoneChangedAndReset(manualSuggestion);
assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
@Test
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void testManualSuggestion_autoTimeEnabled_userRestrictions(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal config =
new ConfigurationInternal.Builder(CONFIG_USER_RESTRICTED_AUTO_ENABLED)
.setUserConfigAllowed(userConfigAllowed)
.build();
Script script = new Script()
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
// User is restricted so the manual suggestion should be ignored.
boolean expectedResult = false;
script.simulateManualTimeZoneSuggestion(USER_ID, createManualSuggestion("Europe/Paris"),
bypassUserPolicyChecks, expectedResult)
.verifyTimeZoneNotChanged();
assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
@Test
@Parameters({ "true,true", "true,false", "false,true", "false,false" })
public void testManualSuggestion_autoTimeDisabled_userRestrictions(
boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
ConfigurationInternal config =
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED_GEO_DISABLED)
.setUserConfigAllowed(userConfigAllowed)
.build();
Script script = new Script()
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
boolean expectedResult = userConfigAllowed || bypassUserPolicyChecks;
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult);
if (expectedResult) {
script.verifyTimeZoneChangedAndReset(manualSuggestion);
assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion());
} else {
script.verifyTimeZoneNotChanged();
assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion());
}
}
@Test
public void testGeoSuggestion_uncertain() {
Script script = new Script()
@@ -1071,8 +1081,10 @@ public class TimeZoneDetectorStrategyImplTest {
// Make sure the manual suggestion is recorded.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Zone1");
script.simulateManualTimeZoneSuggestion(USER_ID, manualSuggestion,
true /* expectedResult */)
boolean bypassUserPolicyChecks = false;
boolean expectedResult = true;
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult)
.verifyTimeZoneChangedAndReset(manualSuggestion);
expectedDeviceTimeZoneId = manualSuggestion.getZoneId();
assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
@@ -1350,9 +1362,9 @@ public class TimeZoneDetectorStrategyImplTest {
/** Simulates the time zone detection strategy receiving a user-originated suggestion. */
Script simulateManualTimeZoneSuggestion(
@UserIdInt int userId, ManualTimeZoneSuggestion manualTimeZoneSuggestion,
boolean expectedResult) {
boolean bypassUserPolicyChecks, boolean expectedResult) {
boolean actualResult = mTimeZoneDetectorStrategy.suggestManualTimeZone(
userId, manualTimeZoneSuggestion);
userId, manualTimeZoneSuggestion, bypassUserPolicyChecks);
assertEquals(expectedResult, actualResult);
return this;
}