diff options
| author | 2020-09-30 14:46:11 +0000 | |
|---|---|---|
| committer | 2020-09-30 14:46:11 +0000 | |
| commit | e23fca65cd63c96fe31bd84a06d3095fcef5b412 (patch) | |
| tree | 9ab463517a6a2fb0f1969dd4b0380042aec715e8 | |
| parent | b3e2b63d91c20345c279f9cbd257167efba23383 (diff) | |
| parent | 02d943f44d4ed11a7cde1fa33a4c0c07b9cb7e3c (diff) | |
Merge "Get ready to add System APIs for use by SUW"
26 files changed, 988 insertions, 717 deletions
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index d50cdeed6d73..9100d577fd68 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -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 diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/time/ITimeZoneDetectorListener.aidl index 6d0fe72b9de1..723ad5969afc 100644 --- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl +++ b/core/java/android/app/time/ITimeZoneDetectorListener.aidl @@ -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(); }
\ No newline at end of file diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING new file mode 100644 index 000000000000..951905bcbac5 --- /dev/null +++ b/core/java/android/app/time/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.app.time." + } + ] + } + ] +} diff --git a/core/java/android/app/time/TimeManager.java b/core/java/android/app/time/TimeManager.java new file mode 100644 index 000000000000..9864afba534a --- /dev/null +++ b/core/java/android/app/time/TimeManager.java @@ -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; + } + } + } + } +} diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl b/core/java/android/app/time/TimeZoneCapabilities.aidl index fede6458318a..f744bf162c67 100644 --- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.aidl +++ b/core/java/android/app/time/TimeZoneCapabilities.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.app.timezonedetector; +package android.app.time; parcelable TimeZoneCapabilities; diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java index 09fffe9f4f25..c62c2b34f35d 100644 --- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java +++ b/core/java/android/app/time/TimeZoneCapabilities.java @@ -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); } diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl new file mode 100644 index 000000000000..d7b6b58bf85a --- /dev/null +++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.aidl @@ -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; diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java new file mode 100644 index 000000000000..6a04f3f277ed --- /dev/null +++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java @@ -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 + + '}'; + } +} diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl b/core/java/android/app/time/TimeZoneConfiguration.aidl index 62240ba5946b..8e859299d073 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.aidl +++ b/core/java/android/app/time/TimeZoneConfiguration.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.app.timezonedetector; +package android.app.time; parcelable TimeZoneConfiguration; diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/time/TimeZoneConfiguration.java index e879091cd68e..488818a528ef 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java +++ b/core/java/android/app/time/TimeZoneConfiguration.java @@ -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,9 +104,10 @@ 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); @@ -122,21 +115,39 @@ public final class TimeZoneConfiguration implements Parcelable { } /** + * 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; diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl index 4f7e1f62928a..af0389a14c4b 100644 --- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl +++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl @@ -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); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index 2b1cbf259c55..486232d0f6ed 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -30,70 +30,6 @@ import android.content.Context; 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}. * * @hide diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java index 4c69732abec9..3bd6b4bd692a 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java @@ -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,108 +34,12 @@ 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) { Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 005648ffec36..666ba32d0e4f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -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; @@ -5090,6 +5091,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 */ diff --git a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java new file mode 100644 index 000000000000..01a25b27baf6 --- /dev/null +++ b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java @@ -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)); + } +} diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java index faf908de8d4a..3948eb86c4f6 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java +++ b/core/tests/coretests/src/android/app/time/TimeZoneConfigurationTest.java @@ -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); diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java deleted file mode 100644 index db127c6cb9ed..000000000000 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java +++ /dev/null @@ -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)); - } -} diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index b68c54fc6365..9e76bc19360f 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -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(); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java index 0a4f5474e4b4..964dbecf705c 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java @@ -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); } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index b72cb546aae4..6e1f89b3919d 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -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() { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index f944c5638fa9..0b1d6d71ea7b 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -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 diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index 743baedb00e1..781668bebbc9 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -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()); diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java index d7ed96fd5833..54b5bee9a6ab 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java @@ -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()); } } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java index 4ef20829f2dc..bad380acf4b3 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java @@ -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. diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 27b04b6ab17d..cb27657f8364 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -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(); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index 1cdf19319209..296aa73f9c45 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -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; } |