Merge "Get ready to add System APIs for use by SUW"
This commit is contained in:
@@ -33,6 +33,7 @@ import android.app.prediction.AppPredictionManager;
|
||||
import android.app.role.RoleControllerManager;
|
||||
import android.app.role.RoleManager;
|
||||
import android.app.slice.SliceManager;
|
||||
import android.app.time.TimeManager;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.app.timedetector.TimeDetectorImpl;
|
||||
import android.app.timezone.RulesManager;
|
||||
@@ -1218,6 +1219,14 @@ public final class SystemServiceRegistry {
|
||||
return new TimeZoneDetectorImpl();
|
||||
}});
|
||||
|
||||
registerService(Context.TIME_MANAGER, TimeManager.class,
|
||||
new CachedServiceFetcher<TimeManager>() {
|
||||
@Override
|
||||
public TimeManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
return new TimeManager();
|
||||
}});
|
||||
|
||||
registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
|
||||
new CachedServiceFetcher<PermissionManager>() {
|
||||
@Override
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
package android.app.time;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface ITimeZoneConfigurationListener {
|
||||
oneway interface ITimeZoneDetectorListener {
|
||||
void onChange();
|
||||
}
|
||||
12
core/java/android/app/time/TEST_MAPPING
Normal file
12
core/java/android/app/time/TEST_MAPPING
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "FrameworksCoreTests",
|
||||
"options": [
|
||||
{
|
||||
"include-filter": "android.app.time."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
216
core/java/android/app/time/TimeManager.java
Normal file
216
core/java/android/app/time/TimeManager.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemService;
|
||||
import android.app.timezonedetector.ITimeZoneDetectorService;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* The interface through which system components can interact with time and time zone services.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// @SystemApi
|
||||
@SystemService(Context.TIME_MANAGER)
|
||||
public final class TimeManager {
|
||||
private static final String TAG = "time.TimeManager";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final ITimeZoneDetectorService mITimeZoneDetectorService;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ITimeZoneDetectorListener mTimeZoneDetectorReceiver;
|
||||
|
||||
/**
|
||||
* The registered listeners. The key is the actual listener that was registered, the value is a
|
||||
* wrapper that ensures the listener is executed on the correct Executor.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private ArrayMap<TimeZoneDetectorListener, TimeZoneDetectorListener> mTimeZoneDetectorListeners;
|
||||
|
||||
/** @hide */
|
||||
public TimeManager() throws ServiceNotFoundException {
|
||||
// TimeManager is an API over one or possibly more services. At least until there's an
|
||||
// internal refactoring.
|
||||
mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling user's time zone capabilities and configuration.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
|
||||
@NonNull
|
||||
public TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getTimeZoneCapabilities called");
|
||||
}
|
||||
try {
|
||||
return mITimeZoneDetectorService.getCapabilitiesAndConfig();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the time zone detection configuration.
|
||||
*
|
||||
* <p>Configuration settings vary in scope: some may be global (affect all users), others may be
|
||||
* specific to the current user.
|
||||
*
|
||||
* <p>The ability to modify configuration settings can be subject to restrictions. For
|
||||
* example, they may be determined by device hardware, general policy (i.e. only the primary
|
||||
* user can set them), or by a managed device policy. Use {@link
|
||||
* #getTimeZoneCapabilitiesAndConfig()} to obtain information at runtime about the user's
|
||||
* capabilities.
|
||||
*
|
||||
* <p>Attempts to modify configuration settings with capabilities that are {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
|
||||
* will be returned. Modifying configuration settings with capabilities that are {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
|
||||
* TimeZoneCapabilities} for further details.
|
||||
*
|
||||
* <p>If the supplied configuration only has some values set, then only the specified settings
|
||||
* will be updated (where the user's capabilities allow) and other settings will be left
|
||||
* unchanged.
|
||||
*
|
||||
* @return {@code true} if all the configuration settings specified have been set to the
|
||||
* new values, {@code false} if none have
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
|
||||
public boolean updateTimeZoneConfiguration(@NonNull TimeZoneConfiguration configuration) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updateConfiguration called: " + configuration);
|
||||
}
|
||||
try {
|
||||
return mITimeZoneDetectorService.updateConfiguration(configuration);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface that can be used to listen for changes to the time zone detector behavior.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TimeZoneDetectorListener {
|
||||
/**
|
||||
* Called when something about the time zone detector behavior on the device has changed.
|
||||
* For example, this could be because the current user has switched, one of the global or
|
||||
* user's settings been changed, or something that could affect a user's capabilities with
|
||||
* respect to the time zone detector has changed. Because different users can have different
|
||||
* configuration and capabilities, this method may be called when nothing has changed for
|
||||
* the receiving user.
|
||||
*/
|
||||
void onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener that will be informed when something about the time zone detector
|
||||
* behavior changes.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
|
||||
public void addTimeZoneDetectorListener(@NonNull Executor executor,
|
||||
@NonNull TimeZoneDetectorListener listener) {
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "addTimeZoneDetectorListener called: " + listener);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (mTimeZoneDetectorListeners == null) {
|
||||
mTimeZoneDetectorListeners = new ArrayMap<>();
|
||||
} else if (mTimeZoneDetectorListeners.containsKey(listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTimeZoneDetectorReceiver == null) {
|
||||
ITimeZoneDetectorListener iListener = new ITimeZoneDetectorListener.Stub() {
|
||||
@Override
|
||||
public void onChange() {
|
||||
notifyTimeZoneDetectorListeners();
|
||||
}
|
||||
};
|
||||
mTimeZoneDetectorReceiver = iListener;
|
||||
try {
|
||||
mITimeZoneDetectorService.addListener(mTimeZoneDetectorReceiver);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
mTimeZoneDetectorListeners.put(listener, () -> executor.execute(listener::onChange));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTimeZoneDetectorListeners() {
|
||||
ArrayMap<TimeZoneDetectorListener, TimeZoneDetectorListener> timeZoneDetectorListeners;
|
||||
synchronized (mLock) {
|
||||
if (mTimeZoneDetectorListeners == null || mTimeZoneDetectorListeners.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
timeZoneDetectorListeners = new ArrayMap<>(mTimeZoneDetectorListeners);
|
||||
}
|
||||
int size = timeZoneDetectorListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
timeZoneDetectorListeners.valueAt(i).onChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener previously passed to
|
||||
* {@link #addTimeZoneDetectorListener(Executor, TimeZoneDetectorListener)}
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
|
||||
public void removeTimeZoneDetectorListener(@NonNull TimeZoneDetectorListener listener) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "removeConfigurationListener called: " + listener);
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mTimeZoneDetectorListeners == null || mTimeZoneDetectorListeners.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mTimeZoneDetectorListeners.remove(listener);
|
||||
|
||||
// If the last local listener has been removed, remove and discard the
|
||||
// mTimeZoneDetectorReceiver.
|
||||
if (mTimeZoneDetectorListeners.isEmpty()) {
|
||||
try {
|
||||
mITimeZoneDetectorService.removeListener(mTimeZoneDetectorReceiver);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} finally {
|
||||
mTimeZoneDetectorReceiver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
package android.app.time;
|
||||
|
||||
parcelable TimeZoneCapabilities;
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED;
|
||||
import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED;
|
||||
package android.app.time;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneDetector;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -42,15 +42,18 @@ import java.util.Objects;
|
||||
* <p>Actions have associated methods, see the documentation for each action for details.
|
||||
*
|
||||
* <p>For configuration settings capabilities, the associated settings value can be found via
|
||||
* {@link #getConfiguration()} and may be changed using {@link
|
||||
* TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow).
|
||||
* {@link TimeManager#getTimeZoneCapabilitiesAndConfig()} and may be changed using {@link
|
||||
* TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} (if the user's capabilities
|
||||
* allow).
|
||||
*
|
||||
* <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// @SystemApi
|
||||
public final class TimeZoneCapabilities implements Parcelable {
|
||||
|
||||
/** @hide */
|
||||
@IntDef({ CAPABILITY_NOT_SUPPORTED, CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_APPLICABLE,
|
||||
CAPABILITY_POSSESSED })
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -94,64 +97,60 @@ public final class TimeZoneCapabilities implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@NonNull private final TimeZoneConfiguration mConfiguration;
|
||||
private final @CapabilityState int mConfigureAutoDetectionEnabled;
|
||||
private final @CapabilityState int mConfigureGeoDetectionEnabled;
|
||||
private final @CapabilityState int mSuggestManualTimeZone;
|
||||
/**
|
||||
* The user the capabilities are for. This is used for object equality and debugging but there
|
||||
* is no accessor.
|
||||
*/
|
||||
@NonNull private final UserHandle mUserHandle;
|
||||
private final @CapabilityState int mConfigureAutoDetectionEnabledCapability;
|
||||
private final @CapabilityState int mConfigureGeoDetectionEnabledCapability;
|
||||
private final @CapabilityState int mSuggestManualTimeZoneCapability;
|
||||
|
||||
private TimeZoneCapabilities(@NonNull Builder builder) {
|
||||
this.mConfiguration = Objects.requireNonNull(builder.mConfiguration);
|
||||
this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
|
||||
this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
|
||||
this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
|
||||
this.mUserHandle = Objects.requireNonNull(builder.mUserHandle);
|
||||
this.mConfigureAutoDetectionEnabledCapability =
|
||||
builder.mConfigureAutoDetectionEnabledCapability;
|
||||
this.mConfigureGeoDetectionEnabledCapability =
|
||||
builder.mConfigureGeoDetectionEnabledCapability;
|
||||
this.mSuggestManualTimeZoneCapability = builder.mSuggestManualTimeZoneCapability;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static TimeZoneCapabilities createFromParcel(Parcel in) {
|
||||
return new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(in.readParcelable(null))
|
||||
.setConfigureAutoDetectionEnabled(in.readInt())
|
||||
.setConfigureGeoDetectionEnabled(in.readInt())
|
||||
.setSuggestManualTimeZone(in.readInt())
|
||||
UserHandle userHandle = UserHandle.readFromParcel(in);
|
||||
return new TimeZoneCapabilities.Builder(userHandle)
|
||||
.setConfigureAutoDetectionEnabledCapability(in.readInt())
|
||||
.setConfigureGeoDetectionEnabledCapability(in.readInt())
|
||||
.setSuggestManualTimeZoneCapability(in.readInt())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mConfiguration, flags);
|
||||
dest.writeInt(mConfigureAutoDetectionEnabled);
|
||||
dest.writeInt(mConfigureGeoDetectionEnabled);
|
||||
dest.writeInt(mSuggestManualTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's time zone behavior configuration.
|
||||
*/
|
||||
public @NonNull TimeZoneConfiguration getConfiguration() {
|
||||
return mConfiguration;
|
||||
UserHandle.writeToParcel(mUserHandle, dest);
|
||||
dest.writeInt(mConfigureAutoDetectionEnabledCapability);
|
||||
dest.writeInt(mConfigureGeoDetectionEnabledCapability);
|
||||
dest.writeInt(mSuggestManualTimeZoneCapability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capability state associated with the user's ability to modify the automatic time
|
||||
* zone detection setting. The setting can be updated via {@link
|
||||
* TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
|
||||
* #getConfiguration()}.
|
||||
* TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}.
|
||||
*/
|
||||
@CapabilityState
|
||||
public int getConfigureAutoDetectionEnabled() {
|
||||
return mConfigureAutoDetectionEnabled;
|
||||
public int getConfigureAutoDetectionEnabledCapability() {
|
||||
return mConfigureAutoDetectionEnabledCapability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capability state associated with the user's ability to modify the geolocation
|
||||
* detection setting. The setting can be updated via {@link
|
||||
* TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
|
||||
* #getConfiguration()}.
|
||||
* TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}.
|
||||
*/
|
||||
@CapabilityState
|
||||
public int getConfigureGeoDetectionEnabled() {
|
||||
return mConfigureGeoDetectionEnabled;
|
||||
public int getConfigureGeoDetectionEnabledCapability() {
|
||||
return mConfigureGeoDetectionEnabledCapability;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,36 +159,37 @@ public final class TimeZoneCapabilities implements Parcelable {
|
||||
*
|
||||
* <p>The suggestion will be ignored in all cases unless the value is {@link
|
||||
* #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@CapabilityState
|
||||
public int getSuggestManualTimeZone() {
|
||||
return mSuggestManualTimeZone;
|
||||
public int getSuggestManualTimeZoneCapability() {
|
||||
return mSuggestManualTimeZoneCapability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of
|
||||
* {@code requestedChanges}, if the current capabilities allow. The new configuration is
|
||||
* returned and the capabilities are left unchanged. If the capabilities do not permit one or
|
||||
* more of the changes then {@code null} is returned.
|
||||
* Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of
|
||||
* {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is
|
||||
* returned. If the capabilities do not permit one or more of the requested changes then {@code
|
||||
* null} is returned.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) {
|
||||
if (requestedChanges.getUserId() != mConfiguration.getUserId()) {
|
||||
throw new IllegalArgumentException("User does not match:"
|
||||
+ " this=" + mConfiguration + ", other=" + requestedChanges);
|
||||
}
|
||||
|
||||
public TimeZoneConfiguration tryApplyConfigChanges(
|
||||
@NonNull TimeZoneConfiguration config,
|
||||
@NonNull TimeZoneConfiguration requestedChanges) {
|
||||
TimeZoneConfiguration.Builder newConfigBuilder =
|
||||
new TimeZoneConfiguration.Builder(mConfiguration);
|
||||
if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) {
|
||||
if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
|
||||
new TimeZoneConfiguration.Builder(config);
|
||||
if (requestedChanges.hasIsAutoDetectionEnabled()) {
|
||||
if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) {
|
||||
return null;
|
||||
}
|
||||
newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
|
||||
}
|
||||
|
||||
if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) {
|
||||
if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
|
||||
if (requestedChanges.hasIsGeoDetectionEnabled()) {
|
||||
if (this.getConfigureGeoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) {
|
||||
return null;
|
||||
}
|
||||
newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
|
||||
@@ -212,71 +212,71 @@ public final class TimeZoneCapabilities implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
TimeZoneCapabilities that = (TimeZoneCapabilities) o;
|
||||
return Objects.equals(mConfiguration, that.mConfiguration)
|
||||
&& mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
|
||||
&& mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
|
||||
&& mSuggestManualTimeZone == that.mSuggestManualTimeZone;
|
||||
return mUserHandle.equals(that.mUserHandle)
|
||||
&& mConfigureAutoDetectionEnabledCapability
|
||||
== that.mConfigureAutoDetectionEnabledCapability
|
||||
&& mConfigureGeoDetectionEnabledCapability
|
||||
== that.mConfigureGeoDetectionEnabledCapability
|
||||
&& mSuggestManualTimeZoneCapability == that.mSuggestManualTimeZoneCapability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mConfiguration,
|
||||
mConfigureAutoDetectionEnabled,
|
||||
mConfigureGeoDetectionEnabled,
|
||||
mSuggestManualTimeZone);
|
||||
return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability,
|
||||
mConfigureGeoDetectionEnabledCapability, mSuggestManualTimeZoneCapability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneDetectorCapabilities{"
|
||||
+ "mConfiguration=" + mConfiguration
|
||||
+ ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
|
||||
+ ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
|
||||
+ ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
|
||||
+ "mUserHandle=" + mUserHandle
|
||||
+ ", mConfigureAutoDetectionEnabledCapability="
|
||||
+ mConfigureAutoDetectionEnabledCapability
|
||||
+ ", mConfigureGeoDetectionEnabledCapability="
|
||||
+ mConfigureGeoDetectionEnabledCapability
|
||||
+ ", mSuggestManualTimeZoneCapability=" + mSuggestManualTimeZoneCapability
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class Builder {
|
||||
|
||||
private TimeZoneConfiguration mConfiguration;
|
||||
private @CapabilityState int mConfigureAutoDetectionEnabled;
|
||||
private @CapabilityState int mConfigureGeoDetectionEnabled;
|
||||
private @CapabilityState int mSuggestManualTimeZone;
|
||||
@NonNull private UserHandle mUserHandle;
|
||||
private @CapabilityState int mConfigureAutoDetectionEnabledCapability;
|
||||
private @CapabilityState int mConfigureGeoDetectionEnabledCapability;
|
||||
private @CapabilityState int mSuggestManualTimeZoneCapability;
|
||||
|
||||
/** Sets the user-visible configuration settings. */
|
||||
public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) {
|
||||
if (!configuration.isComplete()) {
|
||||
throw new IllegalArgumentException(configuration + " is not complete");
|
||||
}
|
||||
this.mConfiguration = configuration;
|
||||
return this;
|
||||
public Builder(@NonNull UserHandle userHandle) {
|
||||
mUserHandle = Objects.requireNonNull(userHandle);
|
||||
}
|
||||
|
||||
/** Sets the state for the automatic time zone detection enabled config. */
|
||||
public Builder setConfigureAutoDetectionEnabled(@CapabilityState int value) {
|
||||
this.mConfigureAutoDetectionEnabled = value;
|
||||
public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) {
|
||||
this.mConfigureAutoDetectionEnabledCapability = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the state for the geolocation time zone detection enabled config. */
|
||||
public Builder setConfigureGeoDetectionEnabled(@CapabilityState int value) {
|
||||
this.mConfigureGeoDetectionEnabled = value;
|
||||
public Builder setConfigureGeoDetectionEnabledCapability(@CapabilityState int value) {
|
||||
this.mConfigureGeoDetectionEnabledCapability = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the state for the suggestManualTimeZone action. */
|
||||
public Builder setSuggestManualTimeZone(@CapabilityState int value) {
|
||||
this.mSuggestManualTimeZone = value;
|
||||
public Builder setSuggestManualTimeZoneCapability(@CapabilityState int value) {
|
||||
this.mSuggestManualTimeZoneCapability = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns the {@link TimeZoneCapabilities}. */
|
||||
@NonNull
|
||||
public TimeZoneCapabilities build() {
|
||||
verifyCapabilitySet(mConfigureAutoDetectionEnabled, "configureAutoDetectionEnabled");
|
||||
verifyCapabilitySet(mConfigureGeoDetectionEnabled, "configureGeoDetectionEnabled");
|
||||
verifyCapabilitySet(mSuggestManualTimeZone, "suggestManualTimeZone");
|
||||
verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability,
|
||||
"configureAutoDetectionEnabledCapability");
|
||||
verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability,
|
||||
"configureGeoDetectionEnabledCapability");
|
||||
verifyCapabilitySet(mSuggestManualTimeZoneCapability,
|
||||
"suggestManualTimeZoneCapability");
|
||||
return new TimeZoneCapabilities(this);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
parcelable TimeZoneCapabilitiesAndConfig;
|
||||
119
core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
Normal file
119
core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A pair containing a user's {@link TimeZoneCapabilities} and {@link TimeZoneConfiguration}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// @SystemApi
|
||||
public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
|
||||
|
||||
public static final @NonNull Creator<TimeZoneCapabilitiesAndConfig> CREATOR =
|
||||
new Creator<TimeZoneCapabilitiesAndConfig>() {
|
||||
public TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
|
||||
return TimeZoneCapabilitiesAndConfig.createFromParcel(in);
|
||||
}
|
||||
|
||||
public TimeZoneCapabilitiesAndConfig[] newArray(int size) {
|
||||
return new TimeZoneCapabilitiesAndConfig[size];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@NonNull private final TimeZoneCapabilities mCapabilities;
|
||||
@NonNull private final TimeZoneConfiguration mConfiguration;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public TimeZoneCapabilitiesAndConfig(
|
||||
@NonNull TimeZoneCapabilities capabilities,
|
||||
@NonNull TimeZoneConfiguration configuration) {
|
||||
this.mCapabilities = Objects.requireNonNull(capabilities);
|
||||
this.mConfiguration = Objects.requireNonNull(configuration);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
|
||||
TimeZoneCapabilities capabilities = in.readParcelable(null);
|
||||
TimeZoneConfiguration configuration = in.readParcelable(null);
|
||||
return new TimeZoneCapabilitiesAndConfig(capabilities, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mCapabilities, flags);
|
||||
dest.writeParcelable(mConfiguration, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's time zone behavior capabilities.
|
||||
*/
|
||||
@NonNull
|
||||
public TimeZoneCapabilities getCapabilities() {
|
||||
return mCapabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's time zone behavior configuration.
|
||||
*/
|
||||
@NonNull
|
||||
public TimeZoneConfiguration getConfiguration() {
|
||||
return mConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TimeZoneCapabilitiesAndConfig that = (TimeZoneCapabilitiesAndConfig) o;
|
||||
return mCapabilities.equals(that.mCapabilities)
|
||||
&& mConfiguration.equals(that.mConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mCapabilities, mConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneDetectorCapabilitiesAndConfig{"
|
||||
+ "mCapabilities=" + mCapabilities
|
||||
+ ", mConfiguration=" + mConfiguration
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
package android.app.time;
|
||||
|
||||
parcelable TimeZoneConfiguration;
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
package android.app.time;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.StringDef;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -36,15 +35,13 @@ import java.util.Objects;
|
||||
* several settings, the device behavior may not be directly affected by the setting value.
|
||||
*
|
||||
* <p>Settings can be left absent when updating configuration via {@link
|
||||
* TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be
|
||||
* TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} and those settings will not be
|
||||
* changed. Not all configuration settings can be modified by all users: see {@link
|
||||
* TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details.
|
||||
*
|
||||
* <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence
|
||||
* of individual settings.
|
||||
* TimeManager#getTimeZoneCapabilitiesAndConfig()} and {@link TimeZoneCapabilities} for details.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// @SystemApi
|
||||
public final class TimeZoneConfiguration implements Parcelable {
|
||||
|
||||
public static final @NonNull Creator<TimeZoneConfiguration> CREATOR =
|
||||
@@ -58,53 +55,48 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
/** All configuration properties */
|
||||
/**
|
||||
* All configuration properties
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED })
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface Setting {}
|
||||
|
||||
/** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */
|
||||
@Setting
|
||||
public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
|
||||
private static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
|
||||
|
||||
/** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
|
||||
@Setting
|
||||
public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
|
||||
private static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
|
||||
|
||||
private final @UserIdInt int mUserId;
|
||||
@NonNull private final Bundle mBundle;
|
||||
|
||||
private TimeZoneConfiguration(Builder builder) {
|
||||
this.mUserId = builder.mUserId;
|
||||
this.mBundle = Objects.requireNonNull(builder.mBundle);
|
||||
}
|
||||
|
||||
private static TimeZoneConfiguration createFromParcel(Parcel in) {
|
||||
return new TimeZoneConfiguration.Builder(in.readInt())
|
||||
return new TimeZoneConfiguration.Builder()
|
||||
.setPropertyBundleInternal(in.readBundle())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mUserId);
|
||||
dest.writeBundle(mBundle);
|
||||
}
|
||||
|
||||
/** Returns the ID of the user this configuration is associated with. */
|
||||
public @UserIdInt int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if all known settings are present. */
|
||||
/**
|
||||
* Returns {@code true} if all known settings are present.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
return hasSetting(SETTING_AUTO_DETECTION_ENABLED)
|
||||
&& hasSetting(SETTING_GEO_DETECTION_ENABLED);
|
||||
}
|
||||
|
||||
/** Returns true if the specified setting is set. */
|
||||
public boolean hasSetting(@Setting String setting) {
|
||||
return mBundle.containsKey(setting);
|
||||
return hasIsAutoDetectionEnabled()
|
||||
&& hasIsGeoDetectionEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,31 +104,50 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
* controls whether a device will attempt to determine the time zone automatically using
|
||||
* contextual information if the device supports auto detection.
|
||||
*
|
||||
* <p>This setting is global and can be updated by some users.
|
||||
* <p>See {@link TimeZoneCapabilities#getConfigureAutoDetectionEnabledCapability()} for how to
|
||||
* tell if the setting is meaningful for the current user at this time.
|
||||
*
|
||||
* @throws IllegalStateException if the setting has not been set
|
||||
* @throws IllegalStateException if the setting is not present
|
||||
*/
|
||||
public boolean isAutoDetectionEnabled() {
|
||||
enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
|
||||
return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the {@link #isAutoDetectionEnabled()} setting is present.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasIsAutoDetectionEnabled() {
|
||||
return mBundle.containsKey(SETTING_AUTO_DETECTION_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This
|
||||
* controls whether a device can use geolocation to determine time zone. Only used when
|
||||
* {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their
|
||||
* location to be used.
|
||||
* controls whether the device can use geolocation to determine time zone. This value may only
|
||||
* be used by Android under some circumstances. For example, it is not used when
|
||||
* {@link #isGeoDetectionEnabled()} is {@code false}.
|
||||
*
|
||||
* <p>This setting is user-scoped and can be updated by some users.
|
||||
* See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}.
|
||||
* <p>See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabledCapability()} for how to
|
||||
* tell if the setting is meaningful for the current user at this time.
|
||||
*
|
||||
* @throws IllegalStateException if the setting has not been set
|
||||
* @throws IllegalStateException if the setting is not present
|
||||
*/
|
||||
public boolean isGeoDetectionEnabled() {
|
||||
enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED);
|
||||
return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the {@link #isGeoDetectionEnabled()} setting is present.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasIsGeoDetectionEnabled() {
|
||||
return mBundle.containsKey(SETTING_GEO_DETECTION_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -151,20 +162,18 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
TimeZoneConfiguration that = (TimeZoneConfiguration) o;
|
||||
return mUserId == that.mUserId
|
||||
&& mBundle.kindofEquals(that.mBundle);
|
||||
return mBundle.kindofEquals(that.mBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mUserId, mBundle);
|
||||
return Objects.hash(mBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneConfiguration{"
|
||||
+ "mUserId=" + mUserId
|
||||
+ ", mBundle=" + mBundle
|
||||
+ "mBundle=" + mBundle
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -174,43 +183,43 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class Builder {
|
||||
/**
|
||||
* A builder for {@link TimeZoneConfiguration} objects.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// @SystemApi
|
||||
public static final class Builder {
|
||||
|
||||
private final @UserIdInt int mUserId;
|
||||
private final Bundle mBundle = new Bundle();
|
||||
|
||||
/**
|
||||
* Creates a new Builder for a userId with no settings held.
|
||||
* Creates a new Builder with no settings held.
|
||||
*/
|
||||
public Builder(@UserIdInt int userId) {
|
||||
mUserId = userId;
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Builder by copying the user ID and settings from an existing instance.
|
||||
* Creates a new Builder by copying the settings from an existing instance.
|
||||
*/
|
||||
public Builder(TimeZoneConfiguration toCopy) {
|
||||
this.mUserId = toCopy.mUserId;
|
||||
public Builder(@NonNull TimeZoneConfiguration toCopy) {
|
||||
mergeProperties(toCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges {@code other} settings into this instances, replacing existing values in this
|
||||
* where the settings appear in both.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder mergeProperties(TimeZoneConfiguration other) {
|
||||
if (mUserId != other.mUserId) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot merge configurations for different user IDs."
|
||||
+ " this.mUserId=" + this.mUserId
|
||||
+ ", other.mUserId=" + other.mUserId);
|
||||
}
|
||||
@NonNull
|
||||
public Builder mergeProperties(@NonNull TimeZoneConfiguration other) {
|
||||
this.mBundle.putAll(other.mBundle);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder setPropertyBundleInternal(Bundle bundle) {
|
||||
@NonNull
|
||||
Builder setPropertyBundleInternal(@NonNull Bundle bundle) {
|
||||
this.mBundle.putAll(bundle);
|
||||
return this;
|
||||
}
|
||||
@@ -218,6 +227,7 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
/**
|
||||
* Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAutoDetectionEnabled(boolean enabled) {
|
||||
this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
|
||||
return this;
|
||||
@@ -226,6 +236,7 @@ public final class TimeZoneConfiguration implements Parcelable {
|
||||
/**
|
||||
* Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setGeoDetectionEnabled(boolean enabled) {
|
||||
this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled);
|
||||
return this;
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package android.app.timezonedetector;
|
||||
|
||||
import android.app.timezonedetector.ITimeZoneConfigurationListener;
|
||||
import android.app.time.ITimeZoneDetectorListener;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
|
||||
/**
|
||||
* System private API to communicate with time zone detector service.
|
||||
@@ -35,9 +35,9 @@ import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITimeZoneDetectorService {
|
||||
TimeZoneCapabilities getCapabilities();
|
||||
void addConfigurationListener(ITimeZoneConfigurationListener listener);
|
||||
void removeConfigurationListener(ITimeZoneConfigurationListener listener);
|
||||
TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig();
|
||||
void addListener(ITimeZoneDetectorListener listener);
|
||||
void removeListener(ITimeZoneDetectorListener listener);
|
||||
|
||||
boolean updateConfiguration(in TimeZoneConfiguration configuration);
|
||||
|
||||
|
||||
@@ -29,70 +29,6 @@ import android.content.Context;
|
||||
@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
|
||||
public interface TimeZoneDetector {
|
||||
|
||||
/**
|
||||
* Returns the current user's time zone capabilities. See {@link TimeZoneCapabilities}.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
@NonNull
|
||||
TimeZoneCapabilities getCapabilities();
|
||||
|
||||
/**
|
||||
* Modifies the time zone detection configuration.
|
||||
*
|
||||
* <p>Configuration settings vary in scope: some may be global (affect all users), others may be
|
||||
* specific to the current user.
|
||||
*
|
||||
* <p>The ability to modify configuration settings can be subject to restrictions. For
|
||||
* example, they may be determined by device hardware, general policy (i.e. only the primary
|
||||
* user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain
|
||||
* information at runtime about the user's capabilities.
|
||||
*
|
||||
* <p>Attempts to modify configuration settings with capabilities that are {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
|
||||
* will be returned. Modifying configuration settings with capabilities that are {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
|
||||
* TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
|
||||
* TimeZoneCapabilities} for further details.
|
||||
*
|
||||
* <p>If the supplied configuration only has some values set, then only the specified settings
|
||||
* will be updated (where the user's capabilities allow) and other settings will be left
|
||||
* unchanged.
|
||||
*
|
||||
* @return {@code true} if all the configuration settings specified have been set to the
|
||||
* new values, {@code false} if none have
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
|
||||
|
||||
/**
|
||||
* An interface that can be used to listen for changes to the time zone detector configuration.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface TimeZoneConfigurationListener {
|
||||
/**
|
||||
* Called when something about the time zone configuration on the device has changed.
|
||||
* This could be because the current user has changed, one of the device's relevant settings
|
||||
* has changed, or something that could affect a user's capabilities has changed.
|
||||
* There are no guarantees about the thread used.
|
||||
*/
|
||||
void onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener that will be informed when something about the time zone configuration
|
||||
* changes.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener previously passed to
|
||||
* {@link #addConfigurationListener(ITimeZoneConfigurationListener)}
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
|
||||
|
||||
/**
|
||||
* A shared utility method to create a {@link ManualTimeZoneSuggestion}.
|
||||
*
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -35,107 +34,11 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector {
|
||||
|
||||
private final ITimeZoneDetectorService mITimeZoneDetectorService;
|
||||
|
||||
private ITimeZoneConfigurationListener mConfigurationReceiver;
|
||||
private ArraySet<TimeZoneConfigurationListener> mConfigurationListeners;
|
||||
|
||||
public TimeZoneDetectorImpl() throws ServiceNotFoundException {
|
||||
mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public TimeZoneCapabilities getCapabilities() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getCapabilities called");
|
||||
}
|
||||
try {
|
||||
return mITimeZoneDetectorService.getCapabilities();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updateConfiguration called: " + configuration);
|
||||
}
|
||||
try {
|
||||
return mITimeZoneDetectorService.updateConfiguration(configuration);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "addConfigurationListener called: " + listener);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (mConfigurationListeners.contains(listener)) {
|
||||
return;
|
||||
}
|
||||
if (mConfigurationReceiver == null) {
|
||||
ITimeZoneConfigurationListener iListener =
|
||||
new ITimeZoneConfigurationListener.Stub() {
|
||||
@Override
|
||||
public void onChange() {
|
||||
notifyConfigurationListeners();
|
||||
}
|
||||
};
|
||||
mConfigurationReceiver = iListener;
|
||||
}
|
||||
if (mConfigurationListeners == null) {
|
||||
mConfigurationListeners = new ArraySet<>();
|
||||
}
|
||||
|
||||
boolean wasEmpty = mConfigurationListeners.isEmpty();
|
||||
mConfigurationListeners.add(listener);
|
||||
if (wasEmpty) {
|
||||
try {
|
||||
mITimeZoneDetectorService.addConfigurationListener(mConfigurationReceiver);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyConfigurationListeners() {
|
||||
final ArraySet<TimeZoneConfigurationListener> configurationListeners;
|
||||
synchronized (this) {
|
||||
configurationListeners = new ArraySet<>(mConfigurationListeners);
|
||||
}
|
||||
int size = configurationListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
configurationListeners.valueAt(i).onChange();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "removeConfigurationListener called: " + listener);
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (mConfigurationListeners == null) {
|
||||
return;
|
||||
}
|
||||
boolean wasEmpty = mConfigurationListeners.isEmpty();
|
||||
mConfigurationListeners.remove(listener);
|
||||
if (mConfigurationListeners.isEmpty() && !wasEmpty) {
|
||||
try {
|
||||
mITimeZoneDetectorService.removeConfigurationListener(mConfigurationReceiver);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
|
||||
if (DEBUG) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import android.app.ActivityManager;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
import android.app.VrManager;
|
||||
import android.app.time.TimeManager;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -5089,6 +5090,14 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve an {@link TimeManager}.
|
||||
* @hide
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
*/
|
||||
public static final String TIME_MANAGER = "time_manager";
|
||||
|
||||
/**
|
||||
* Binder service name for {@link AppBindingService}.
|
||||
* @hide
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class TimeZoneCapabilitiesTest {
|
||||
|
||||
private static final UserHandle TEST_USER_HANDLE = UserHandle.of(12345);
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
|
||||
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
|
||||
TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
|
||||
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
|
||||
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryApplyConfigChanges_permitted() {
|
||||
TimeZoneConfiguration oldConfiguration =
|
||||
new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
|
||||
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZoneCapability(CAPABILITY_POSSESSED)
|
||||
.build();
|
||||
|
||||
TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
assertEquals(expected, capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTryApplyConfigChanges_notPermitted() {
|
||||
TimeZoneConfiguration oldConfiguration =
|
||||
new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
|
||||
.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
|
||||
.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
|
||||
.setSuggestManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
|
||||
.build();
|
||||
|
||||
TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
assertNull(capabilities.tryApplyConfigChanges(oldConfiguration, configChange));
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
|
||||
@@ -23,16 +23,20 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class TimeZoneConfigurationTest {
|
||||
|
||||
private static final int ARBITRARY_USER_ID = 9876;
|
||||
|
||||
@Test
|
||||
public void testBuilder_copyConstructor() {
|
||||
TimeZoneConfiguration.Builder builder1 =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true);
|
||||
TimeZoneConfiguration configuration1 = builder1.build();
|
||||
@@ -45,27 +49,27 @@ public class TimeZoneConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void testIntrospectionMethods() {
|
||||
TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build();
|
||||
TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder().build();
|
||||
assertFalse(empty.isComplete());
|
||||
assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
|
||||
assertFalse(empty.hasIsAutoDetectionEnabled());
|
||||
|
||||
TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
assertTrue(completeConfig.isComplete());
|
||||
assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
|
||||
assertTrue(completeConfig.hasIsGeoDetectionEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilder_mergeProperties() {
|
||||
TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
.build();
|
||||
|
||||
{
|
||||
TimeZoneConfiguration mergedEmptyAnd1 =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
new TimeZoneConfiguration.Builder()
|
||||
.mergeProperties(configuration1)
|
||||
.build();
|
||||
assertEquals(configuration1, mergedEmptyAnd1);
|
||||
@@ -73,7 +77,7 @@ public class TimeZoneConfigurationTest {
|
||||
|
||||
{
|
||||
TimeZoneConfiguration configuration2 =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
@@ -90,22 +94,14 @@ public class TimeZoneConfigurationTest {
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TimeZoneConfiguration.Builder builder1 =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
|
||||
new TimeZoneConfiguration.Builder();
|
||||
{
|
||||
TimeZoneConfiguration one = builder1.build();
|
||||
assertEquals(one, one);
|
||||
}
|
||||
|
||||
{
|
||||
TimeZoneConfiguration.Builder differentUserBuilder =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1);
|
||||
TimeZoneConfiguration one = builder1.build();
|
||||
TimeZoneConfiguration two = differentUserBuilder.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
TimeZoneConfiguration.Builder builder2 =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
|
||||
new TimeZoneConfiguration.Builder();
|
||||
{
|
||||
TimeZoneConfiguration one = builder1.build();
|
||||
TimeZoneConfiguration two = builder2.build();
|
||||
@@ -159,7 +155,7 @@ public class TimeZoneConfigurationTest {
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
TimeZoneConfiguration.Builder builder =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
|
||||
new TimeZoneConfiguration.Builder();
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setAutoDetectionEnabled(true);
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TimeZoneCapabilitiesTest {
|
||||
|
||||
private static final int ARBITRARY_USER_ID = 12345;
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(false)
|
||||
.setGeoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(configuration1)
|
||||
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
|
||||
TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(configuration1)
|
||||
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setConfiguration(configuration2);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setConfiguration(configuration2);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
builder2.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
}
|
||||
|
||||
builder1.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
|
||||
{
|
||||
TimeZoneCapabilities one = builder1.build();
|
||||
TimeZoneCapabilities two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(configuration)
|
||||
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
|
||||
builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyUpdate_permitted() {
|
||||
TimeZoneConfiguration oldConfiguration =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(oldConfiguration)
|
||||
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
|
||||
.setSuggestManualTimeZone(CAPABILITY_POSSESSED)
|
||||
.build();
|
||||
assertEquals(oldConfiguration, capabilities.getConfiguration());
|
||||
|
||||
TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
assertEquals(expected, capabilities.applyUpdate(configChange));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyUpdate_notPermitted() {
|
||||
TimeZoneConfiguration oldConfiguration =
|
||||
new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(true)
|
||||
.setGeoDetectionEnabled(true)
|
||||
.build();
|
||||
TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(oldConfiguration)
|
||||
.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
|
||||
.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
|
||||
.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
|
||||
.build();
|
||||
assertEquals(oldConfiguration, capabilities.getConfiguration());
|
||||
|
||||
TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
.setAutoDetectionEnabled(false)
|
||||
.build();
|
||||
|
||||
assertNull(capabilities.applyUpdate(configChange));
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,16 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -32,7 +33,7 @@ import java.util.Objects;
|
||||
/**
|
||||
* Holds all configuration values that affect time zone behavior and some associated logic, e.g.
|
||||
* {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
|
||||
* #createCapabilities()}.
|
||||
* #createCapabilitiesAndConfig()}.
|
||||
*/
|
||||
public final class ConfigurationInternal {
|
||||
|
||||
@@ -106,10 +107,15 @@ public final class ConfigurationInternal {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Creates a {@link TimeZoneCapabilities} object using the configuration values. */
|
||||
public TimeZoneCapabilities createCapabilities() {
|
||||
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
|
||||
.setConfiguration(asConfiguration());
|
||||
/** Creates a {@link TimeZoneCapabilitiesAndConfig} object using the configuration values. */
|
||||
public TimeZoneCapabilitiesAndConfig createCapabilitiesAndConfig() {
|
||||
return new TimeZoneCapabilitiesAndConfig(asCapabilities(), asConfiguration());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TimeZoneCapabilities asCapabilities() {
|
||||
UserHandle userHandle = UserHandle.of(mUserId);
|
||||
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userHandle);
|
||||
|
||||
boolean allowConfigDateTime = isUserConfigAllowed();
|
||||
|
||||
@@ -125,7 +131,7 @@ public final class ConfigurationInternal {
|
||||
} else {
|
||||
configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
|
||||
}
|
||||
builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability);
|
||||
builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
|
||||
|
||||
final int configureGeolocationDetectionEnabledCapability;
|
||||
if (!deviceHasTimeZoneDetection) {
|
||||
@@ -137,7 +143,8 @@ public final class ConfigurationInternal {
|
||||
} else {
|
||||
configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
|
||||
}
|
||||
builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability);
|
||||
builder.setConfigureGeoDetectionEnabledCapability(
|
||||
configureGeolocationDetectionEnabledCapability);
|
||||
|
||||
// The ability to make manual time zone suggestions can also be restricted by policy. With
|
||||
// the current logic above, this could lead to a situation where a device hardware does not
|
||||
@@ -151,14 +158,14 @@ public final class ConfigurationInternal {
|
||||
} else {
|
||||
suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
|
||||
}
|
||||
builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability);
|
||||
builder.setSuggestManualTimeZoneCapability(suggestManualTimeZoneCapability);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** Returns a {@link TimeZoneConfiguration} from the configuration values. */
|
||||
public TimeZoneConfiguration asConfiguration() {
|
||||
return new TimeZoneConfiguration.Builder(mUserId)
|
||||
private TimeZoneConfiguration asConfiguration() {
|
||||
return new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
|
||||
.setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
|
||||
.build();
|
||||
@@ -171,10 +178,10 @@ public final class ConfigurationInternal {
|
||||
*/
|
||||
public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
|
||||
Builder builder = new Builder(this);
|
||||
if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) {
|
||||
if (newConfiguration.hasIsAutoDetectionEnabled()) {
|
||||
builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
|
||||
}
|
||||
if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) {
|
||||
if (newConfiguration.hasIsGeoDetectionEnabled()) {
|
||||
builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
|
||||
}
|
||||
return builder.build();
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -159,7 +159,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeConfiguration(TimeZoneConfiguration configuration) {
|
||||
public void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration configuration) {
|
||||
Objects.requireNonNull(configuration);
|
||||
|
||||
// Avoid writing the auto detection enabled setting for devices that do not support auto
|
||||
@@ -171,7 +171,6 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
|
||||
setAutoDetectionEnabled(autoDetectionEnabled);
|
||||
|
||||
if (mGeoDetectionFeatureEnabled) {
|
||||
final int userId = configuration.getUserId();
|
||||
final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
|
||||
setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
|
||||
}
|
||||
|
||||
@@ -18,18 +18,19 @@ package com.android.server.timezonedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.timezonedetector.ITimeZoneConfigurationListener;
|
||||
import android.app.time.ITimeZoneDetectorListener;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ITimeZoneDetectorService;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -41,7 +42,6 @@ import com.android.server.SystemService;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -109,10 +109,14 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
@NonNull
|
||||
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
|
||||
|
||||
@GuardedBy("mConfigurationListeners")
|
||||
/**
|
||||
* Holds the listeners. The key is the {@link IBinder} associated with the listener, the value
|
||||
* is the listener itself.
|
||||
*/
|
||||
@GuardedBy("mListeners")
|
||||
@NonNull
|
||||
private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners =
|
||||
new ArrayList<>();
|
||||
private final ArrayMap<IBinder, ITimeZoneDetectorListener> mListeners =
|
||||
new ArrayMap<>();
|
||||
|
||||
private static TimeZoneDetectorService create(
|
||||
@NonNull Context context, @NonNull Handler handler,
|
||||
@@ -133,20 +137,22 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
|
||||
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
|
||||
|
||||
// Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when
|
||||
// Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
|
||||
// the configuration changes for any reason.
|
||||
mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public TimeZoneCapabilities getCapabilities() {
|
||||
enforceManageTimeZoneDetectorConfigurationPermission();
|
||||
public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig() {
|
||||
enforceManageTimeZoneDetectorPermission();
|
||||
|
||||
int userId = mCallerIdentityInjector.getCallingUserId();
|
||||
long token = mCallerIdentityInjector.clearCallingIdentity();
|
||||
try {
|
||||
return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities();
|
||||
ConfigurationInternal configurationInternal =
|
||||
mTimeZoneDetectorStrategy.getConfigurationInternal(userId);
|
||||
return configurationInternal.createCapabilitiesAndConfig();
|
||||
} finally {
|
||||
mCallerIdentityInjector.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -154,37 +160,34 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
|
||||
@Override
|
||||
public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
|
||||
enforceManageTimeZoneDetectorConfigurationPermission();
|
||||
enforceManageTimeZoneDetectorPermission();
|
||||
Objects.requireNonNull(configuration);
|
||||
|
||||
int callingUserId = mCallerIdentityInjector.getCallingUserId();
|
||||
if (callingUserId != configuration.getUserId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long token = mCallerIdentityInjector.clearCallingIdentity();
|
||||
try {
|
||||
return mTimeZoneDetectorStrategy.updateConfiguration(configuration);
|
||||
return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration);
|
||||
} finally {
|
||||
mCallerIdentityInjector.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
|
||||
enforceManageTimeZoneDetectorConfigurationPermission();
|
||||
public void addListener(@NonNull ITimeZoneDetectorListener listener) {
|
||||
enforceManageTimeZoneDetectorPermission();
|
||||
Objects.requireNonNull(listener);
|
||||
|
||||
synchronized (mConfigurationListeners) {
|
||||
if (mConfigurationListeners.contains(listener)) {
|
||||
synchronized (mListeners) {
|
||||
IBinder listenerBinder = listener.asBinder();
|
||||
if (mListeners.containsKey(listenerBinder)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Ensure the reference to the listener will be removed if the client process dies.
|
||||
listener.asBinder().linkToDeath(this, 0 /* flags */);
|
||||
listenerBinder.linkToDeath(this, 0 /* flags */);
|
||||
|
||||
// Only add the listener if we can linkToDeath().
|
||||
mConfigurationListeners.add(listener);
|
||||
mListeners.put(listenerBinder, listener);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
|
||||
}
|
||||
@@ -192,21 +195,22 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
|
||||
enforceManageTimeZoneDetectorConfigurationPermission();
|
||||
public void removeListener(@NonNull ITimeZoneDetectorListener listener) {
|
||||
enforceManageTimeZoneDetectorPermission();
|
||||
Objects.requireNonNull(listener);
|
||||
|
||||
synchronized (mConfigurationListeners) {
|
||||
synchronized (mListeners) {
|
||||
IBinder listenerBinder = listener.asBinder();
|
||||
boolean removedListener = false;
|
||||
if (mConfigurationListeners.remove(listener)) {
|
||||
if (mListeners.remove(listenerBinder) != null) {
|
||||
// Stop listening for the client process to die.
|
||||
listener.asBinder().unlinkToDeath(this, 0 /* flags */);
|
||||
listenerBinder.unlinkToDeath(this, 0 /* flags */);
|
||||
removedListener = true;
|
||||
}
|
||||
if (!removedListener) {
|
||||
Slog.w(TAG, "Client asked to remove listener=" + listener
|
||||
+ ", but no listeners were removed."
|
||||
+ " mConfigurationListeners=" + mConfigurationListeners);
|
||||
+ " mListeners=" + mListeners);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,19 +222,18 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when one of the ITimeZoneConfigurationListener processes dies before calling
|
||||
* {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}.
|
||||
* Called when one of the ITimeZoneDetectorListener processes dies before calling
|
||||
* {@link #removeListener(ITimeZoneDetectorListener)}.
|
||||
*/
|
||||
@Override
|
||||
public void binderDied(IBinder who) {
|
||||
synchronized (mConfigurationListeners) {
|
||||
synchronized (mListeners) {
|
||||
boolean removedListener = false;
|
||||
final int listenerCount = mConfigurationListeners.size();
|
||||
final int listenerCount = mListeners.size();
|
||||
for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
|
||||
ITimeZoneConfigurationListener listener =
|
||||
mConfigurationListeners.get(listenerIndex);
|
||||
if (listener.asBinder().equals(who)) {
|
||||
mConfigurationListeners.remove(listenerIndex);
|
||||
IBinder listenerBinder = mListeners.keyAt(listenerIndex);
|
||||
if (listenerBinder.equals(who)) {
|
||||
mListeners.removeAt(listenerIndex);
|
||||
removedListener = true;
|
||||
break;
|
||||
}
|
||||
@@ -238,7 +241,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
if (!removedListener) {
|
||||
Slog.w(TAG, "Notified of binder death for who=" + who
|
||||
+ ", but did not remove any listeners."
|
||||
+ " mConfigurationListeners=" + mConfigurationListeners);
|
||||
+ " mConfigurationListeners=" + mListeners);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,11 +250,10 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
// Configuration has changed, but each user may have a different view of the configuration.
|
||||
// It's possible that this will cause unnecessary notifications but that shouldn't be a
|
||||
// problem.
|
||||
synchronized (mConfigurationListeners) {
|
||||
final int listenerCount = mConfigurationListeners.size();
|
||||
synchronized (mListeners) {
|
||||
final int listenerCount = mListeners.size();
|
||||
for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
|
||||
ITimeZoneConfigurationListener listener =
|
||||
mConfigurationListeners.get(listenerIndex);
|
||||
ITimeZoneDetectorListener listener = mListeners.valueAt(listenerIndex);
|
||||
try {
|
||||
listener.onChange();
|
||||
} catch (RemoteException e) {
|
||||
@@ -302,11 +304,10 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
ipw.flush();
|
||||
}
|
||||
|
||||
private void enforceManageTimeZoneDetectorConfigurationPermission() {
|
||||
// TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission.
|
||||
private void enforceManageTimeZoneDetectorPermission() {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.WRITE_SECURE_SETTINGS,
|
||||
"manage time and time zone configuration");
|
||||
android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
|
||||
"manage time and time zone detection");
|
||||
}
|
||||
|
||||
private void enforceSuggestGeolocationTimeZonePermission() {
|
||||
|
||||
@@ -17,9 +17,9 @@ package com.android.server.timezonedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
/**
|
||||
@@ -96,7 +96,8 @@ public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
|
||||
* <p>This method returns {@code true} if the configuration was changed,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
|
||||
boolean updateConfiguration(
|
||||
@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
|
||||
|
||||
/**
|
||||
* Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
|
||||
|
||||
@@ -15,20 +15,21 @@
|
||||
*/
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.IndentingPrintWriter;
|
||||
@@ -93,7 +94,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* All checks about user capabilities must be done by the caller and
|
||||
* {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
|
||||
*/
|
||||
void storeConfiguration(TimeZoneConfiguration newConfiguration);
|
||||
void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfiguration);
|
||||
}
|
||||
|
||||
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
|
||||
@@ -240,27 +241,26 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean updateConfiguration(
|
||||
public synchronized boolean updateConfiguration(@UserIdInt int userId,
|
||||
@NonNull TimeZoneConfiguration requestedConfiguration) {
|
||||
Objects.requireNonNull(requestedConfiguration);
|
||||
|
||||
int userId = requestedConfiguration.getUserId();
|
||||
TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
getConfigurationInternal(userId).createCapabilitiesAndConfig();
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
TimeZoneConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
|
||||
|
||||
// Create a new configuration builder, and copy across the mutable properties users are
|
||||
// able to modify. Other properties are therefore ignored.
|
||||
final TimeZoneConfiguration newConfiguration =
|
||||
capabilities.applyUpdate(requestedConfiguration);
|
||||
capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
|
||||
if (newConfiguration == null) {
|
||||
// The changes could not be made due to
|
||||
// The changes could not be made because the user's capabilities do not allow it.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the configuration / notify as needed. This will cause the mCallback to invoke
|
||||
// handleConfigChanged() asynchronously.
|
||||
mCallback.storeConfiguration(newConfiguration);
|
||||
mCallback.storeConfiguration(userId, newConfiguration);
|
||||
|
||||
TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration();
|
||||
String logMsg = "Configuration changed:"
|
||||
+ " oldConfiguration=" + oldConfiguration
|
||||
+ ", newConfiguration=" + newConfiguration;
|
||||
@@ -313,8 +313,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
String timeZoneId = suggestion.getZoneId();
|
||||
String cause = "Manual time suggestion received: suggestion=" + suggestion;
|
||||
|
||||
TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
|
||||
if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) {
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
getConfigurationInternal(userId).createCapabilitiesAndConfig();
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
if (capabilities.getSuggestManualTimeZoneCapability() != CAPABILITY_POSSESSED) {
|
||||
Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
|
||||
+ ", capabilities=" + capabilities
|
||||
+ ", timeZoneId=" + timeZoneId
|
||||
@@ -605,7 +607,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
ipw.println("mCallback.getCurrentUserId()=" + currentUserId);
|
||||
ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId);
|
||||
ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration);
|
||||
ipw.println("[Capabilities=" + configuration.createCapabilities() + "]");
|
||||
ipw.println("[Capabilities=" + configuration.createCapabilitiesAndConfig() + "]");
|
||||
ipw.println("mCallback.isDeviceTimeZoneInitialized()="
|
||||
+ mCallback.isDeviceTimeZoneInitialized());
|
||||
ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
|
||||
|
||||
@@ -16,22 +16,23 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
|
||||
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
|
||||
import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and
|
||||
* {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it.
|
||||
* Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilitiesAndConfig}.
|
||||
*/
|
||||
public class ConfigurationInternalTest {
|
||||
|
||||
@@ -59,13 +60,20 @@ public class ConfigurationInternalTest {
|
||||
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
|
||||
assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOnConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_POSSESSED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_POSSESSED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_APPLICABLE,
|
||||
capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertTrue(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -77,13 +85,20 @@ public class ConfigurationInternalTest {
|
||||
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
|
||||
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOffConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_POSSESSED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_POSSESSED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_POSSESSED,
|
||||
capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertFalse(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,13 +121,20 @@ public class ConfigurationInternalTest {
|
||||
assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
|
||||
assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOnConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertTrue(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -124,13 +146,20 @@ public class ConfigurationInternalTest {
|
||||
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
|
||||
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOffConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_ALLOWED,
|
||||
capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertFalse(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,13 +182,19 @@ public class ConfigurationInternalTest {
|
||||
assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
|
||||
assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOnConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertTrue(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
{
|
||||
ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
|
||||
@@ -170,13 +205,19 @@ public class ConfigurationInternalTest {
|
||||
assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
|
||||
assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
|
||||
|
||||
TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
|
||||
assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
|
||||
assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
|
||||
assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
autoOffConfig.createCapabilitiesAndConfig();
|
||||
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED,
|
||||
capabilities.getConfigureAutoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_NOT_SUPPORTED,
|
||||
capabilities.getConfigureGeoDetectionEnabledCapability());
|
||||
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZoneCapability());
|
||||
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
assertFalse(configuration.isAutoDetectionEnabled());
|
||||
assertTrue(configuration.isGeoDetectionEnabled());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneCapabilities;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -67,20 +68,25 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) {
|
||||
public boolean updateConfiguration(
|
||||
@UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges) {
|
||||
assertNotNull(mConfigurationInternal);
|
||||
assertNotNull(requestedChanges);
|
||||
|
||||
// Simulate the real strategy's behavior: the new configuration will be updated to be the
|
||||
// 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.
|
||||
TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities();
|
||||
TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges);
|
||||
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
|
||||
mConfigurationInternal.createCapabilitiesAndConfig();
|
||||
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
|
||||
TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
|
||||
TimeZoneConfiguration newConfiguration =
|
||||
capabilities.tryApplyConfigChanges(configuration, requestedChanges);
|
||||
if (newConfiguration == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!newConfiguration.equals(capabilities.getConfiguration())) {
|
||||
if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
|
||||
mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
|
||||
|
||||
// Note: Unlike the real strategy, the listeners is invoked synchronously.
|
||||
|
||||
@@ -31,10 +31,10 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.timezonedetector.ITimeZoneConfigurationListener;
|
||||
import android.app.time.ITimeZoneDetectorListener;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.HandlerThread;
|
||||
@@ -91,85 +91,85 @@ public class TimeZoneDetectorServiceTest {
|
||||
}
|
||||
|
||||
@Test(expected = SecurityException.class)
|
||||
public void testGetCapabilities_withoutPermission() {
|
||||
public void testGetCapabilitiesAndConfig_withoutPermission() {
|
||||
doThrow(new SecurityException("Mock"))
|
||||
.when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
try {
|
||||
mTimeZoneDetectorService.getCapabilities();
|
||||
mTimeZoneDetectorService.getCapabilitiesAndConfig();
|
||||
fail();
|
||||
} finally {
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCapabilities() {
|
||||
public void testGetCapabilitiesAndConfig() {
|
||||
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
ConfigurationInternal configuration =
|
||||
createConfigurationInternal(true /* autoDetectionEnabled*/);
|
||||
mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
|
||||
|
||||
assertEquals(configuration.createCapabilities(),
|
||||
mTimeZoneDetectorService.getCapabilities());
|
||||
assertEquals(configuration.createCapabilitiesAndConfig(),
|
||||
mTimeZoneDetectorService.getCapabilitiesAndConfig());
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
}
|
||||
|
||||
@Test(expected = SecurityException.class)
|
||||
public void testAddConfigurationListener_withoutPermission() {
|
||||
public void testAddListener_withoutPermission() {
|
||||
doThrow(new SecurityException("Mock"))
|
||||
.when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
|
||||
ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
|
||||
try {
|
||||
mTimeZoneDetectorService.addConfigurationListener(mockListener);
|
||||
mTimeZoneDetectorService.addListener(mockListener);
|
||||
fail();
|
||||
} finally {
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = SecurityException.class)
|
||||
public void testRemoveConfigurationListener_withoutPermission() {
|
||||
public void testRemoveListener_withoutPermission() {
|
||||
doThrow(new SecurityException("Mock"))
|
||||
.when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
|
||||
ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
|
||||
try {
|
||||
mTimeZoneDetectorService.removeConfigurationListener(mockListener);
|
||||
mTimeZoneDetectorService.removeListener(mockListener);
|
||||
fail("Expected a SecurityException");
|
||||
} finally {
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception {
|
||||
public void testListenerRegistrationAndCallbacks() throws Exception {
|
||||
ConfigurationInternal initialConfiguration =
|
||||
createConfigurationInternal(false /* autoDetectionEnabled */);
|
||||
mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
|
||||
|
||||
IBinder mockListenerBinder = mock(IBinder.class);
|
||||
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
|
||||
ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
|
||||
|
||||
{
|
||||
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
when(mockListener.asBinder()).thenReturn(mockListenerBinder);
|
||||
|
||||
mTimeZoneDetectorService.addConfigurationListener(mockListener);
|
||||
mTimeZoneDetectorService.addListener(mockListener);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
verify(mockListener).asBinder();
|
||||
verify(mockListenerBinder).linkToDeath(any(), anyInt());
|
||||
@@ -186,7 +186,7 @@ public class TimeZoneDetectorServiceTest {
|
||||
mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
verify(mockListener).onChange();
|
||||
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
|
||||
@@ -200,10 +200,10 @@ public class TimeZoneDetectorServiceTest {
|
||||
|
||||
// Now remove the listener, change the config again, and verify the listener is not
|
||||
// called.
|
||||
mTimeZoneDetectorService.removeConfigurationListener(mockListener);
|
||||
mTimeZoneDetectorService.removeListener(mockListener);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
verify(mockListener).asBinder();
|
||||
verify(mockListenerBinder).unlinkToDeath(any(), eq(0));
|
||||
@@ -219,7 +219,7 @@ public class TimeZoneDetectorServiceTest {
|
||||
mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
|
||||
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
|
||||
anyString());
|
||||
verify(mockListener, never()).onChange();
|
||||
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
|
||||
@@ -354,7 +354,7 @@ public class TimeZoneDetectorServiceTest {
|
||||
}
|
||||
|
||||
private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
|
||||
return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
|
||||
return new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(autoDetectionEnabled)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
|
||||
import android.app.timezonedetector.TimeZoneConfiguration;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
|
||||
@@ -186,26 +186,27 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
|
||||
|
||||
// Set the configuration with auto detection enabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
|
||||
// Nothing should have happened: it was initialized in this state.
|
||||
script.verifyConfigurationNotChanged();
|
||||
|
||||
// Update the configuration with auto detection disabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
|
||||
|
||||
// The settings should have been changed and the StrategyListener onChange() called.
|
||||
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
|
||||
|
||||
// Update the configuration with auto detection enabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
|
||||
// The settings should have been changed and the StrategyListener onChange() called.
|
||||
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
|
||||
|
||||
// Update the configuration to enable geolocation time zone detection.
|
||||
script.simulateUpdateConfiguration(
|
||||
CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
|
||||
USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
|
||||
|
||||
// The settings should have been changed and the StrategyListener onChange() called.
|
||||
script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
|
||||
@@ -216,20 +217,22 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
|
||||
|
||||
// Try to update the configuration with auto detection disabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
|
||||
|
||||
// The settings should not have been changed: user shouldn't have the capabilities.
|
||||
script.verifyConfigurationNotChanged();
|
||||
|
||||
// Update the configuration with auto detection enabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
|
||||
|
||||
// The settings should not have been changed: user shouldn't have the capabilities.
|
||||
script.verifyConfigurationNotChanged();
|
||||
|
||||
// Try to update the configuration to enable geolocation time zone detection.
|
||||
script.simulateUpdateConfiguration(
|
||||
CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
|
||||
USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
|
||||
|
||||
// The settings should not have been changed: user shouldn't have the capabilities.
|
||||
script.verifyConfigurationNotChanged();
|
||||
@@ -240,13 +243,15 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
|
||||
|
||||
// Try to update the configuration with auto detection disabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
|
||||
|
||||
// The settings should not have been changed: user shouldn't have the capabilities.
|
||||
script.verifyConfigurationNotChanged();
|
||||
|
||||
// Update the configuration with auto detection enabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
|
||||
|
||||
// The settings should not have been changed: user shouldn't have the capabilities.
|
||||
script.verifyConfigurationNotChanged();
|
||||
@@ -389,7 +394,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
// Toggling the time zone setting on should cause the device setting to be set.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
|
||||
|
||||
// When time zone detection is already enabled the suggestion (if it scores highly
|
||||
// enough) should be set immediately.
|
||||
@@ -406,7 +412,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
// Toggling the time zone setting should off should do nothing.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
// Assert internal service state.
|
||||
@@ -588,18 +595,20 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
// Toggling time zone detection should set the device time zone only if the current setting
|
||||
// value is different from the most recent telephony suggestion.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
// Simulate a user turning auto detection off, a new suggestion being made while auto
|
||||
// detection is off, and the user turning it on again.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
|
||||
.simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
// Latest suggestion should be used.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneChangedAndReset(newYorkSuggestion);
|
||||
}
|
||||
|
||||
@@ -784,7 +793,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
|
||||
// Turn off geo detection and verify the latest suggestion is cleared.
|
||||
script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true)
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_GEO_DETECTION_DISABLED, true)
|
||||
.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
|
||||
|
||||
// Assert internal service state.
|
||||
@@ -824,19 +833,21 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Toggling the time zone detection enabled setting on should cause the device setting to be
|
||||
// set from the telephony signal, as we've started with geolocation time zone detection
|
||||
// disabled.
|
||||
script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneChangedAndReset(telephonySuggestion);
|
||||
|
||||
// Changing the detection to enable geo detection won't cause the device tz setting to
|
||||
// change because the geo suggestion is empty.
|
||||
script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
|
||||
|
||||
// Changing the detection to disable geo detection should cause the device tz setting to
|
||||
// change to the telephony suggestion.
|
||||
script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
|
||||
script.simulateUpdateConfiguration(
|
||||
USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneChangedAndReset(telephonySuggestion);
|
||||
|
||||
assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
@@ -898,7 +909,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
private static TimeZoneConfiguration createConfig(
|
||||
@Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
|
||||
TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID);
|
||||
TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder();
|
||||
if (autoDetection != null) {
|
||||
builder.setAutoDetectionEnabled(autoDetection);
|
||||
}
|
||||
@@ -957,9 +968,10 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeConfiguration(TimeZoneConfiguration newConfiguration) {
|
||||
public void storeConfiguration(
|
||||
@UserIdInt int userId, TimeZoneConfiguration newConfiguration) {
|
||||
ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
|
||||
if (newConfiguration.getUserId() != oldConfiguration.getUserId()) {
|
||||
if (userId != oldConfiguration.getUserId()) {
|
||||
fail("FakeCallback does not support multiple users");
|
||||
}
|
||||
|
||||
@@ -1014,9 +1026,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
* the return value.
|
||||
*/
|
||||
Script simulateUpdateConfiguration(
|
||||
TimeZoneConfiguration configuration, boolean expectedResult) {
|
||||
int userId, TimeZoneConfiguration configuration, boolean expectedResult) {
|
||||
assertEquals(expectedResult,
|
||||
mTimeZoneDetectorStrategy.updateConfiguration(configuration));
|
||||
mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user