1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.timezonedetector; 18 19 import static org.junit.Assert.assertNotNull; 20 21 import android.annotation.NonNull; 22 import android.annotation.UserIdInt; 23 import android.app.time.TimeZoneCapabilities; 24 import android.app.time.TimeZoneConfiguration; 25 26 import java.time.Duration; 27 import java.util.ArrayList; 28 import java.util.List; 29 import java.util.Optional; 30 31 /** 32 * A partially implemented, fake implementation of ServiceConfigAccessor for tests. 33 * 34 * <p>This class has rudamentary support for multiple users, but unlike the real thing, it doesn't 35 * simulate that some settings are global and shared between users. It also delivers config updates 36 * synchronously. 37 */ 38 public class FakeServiceConfigAccessor implements ServiceConfigAccessor { 39 40 private final List<StateChangeListener> mConfigurationInternalChangeListeners = 41 new ArrayList<>(); 42 private ConfigurationInternal mCurrentUserConfigurationInternal; 43 private ConfigurationInternal mOtherUserConfigurationInternal; 44 45 @Override addConfigurationInternalChangeListener(StateChangeListener listener)46 public void addConfigurationInternalChangeListener(StateChangeListener listener) { 47 mConfigurationInternalChangeListeners.add(listener); 48 } 49 50 @Override removeConfigurationInternalChangeListener(StateChangeListener listener)51 public void removeConfigurationInternalChangeListener(StateChangeListener listener) { 52 mConfigurationInternalChangeListeners.remove(listener); 53 } 54 55 @Override getCurrentUserConfigurationInternal()56 public ConfigurationInternal getCurrentUserConfigurationInternal() { 57 return getConfigurationInternal(mCurrentUserConfigurationInternal.getUserId()); 58 } 59 60 @Override updateConfiguration( @serIdInt int userId, @NonNull TimeZoneConfiguration requestedChanges, boolean bypassUserPolicyChecks)61 public boolean updateConfiguration( 62 @UserIdInt int userId, @NonNull TimeZoneConfiguration requestedChanges, 63 boolean bypassUserPolicyChecks) { 64 assertNotNull(mCurrentUserConfigurationInternal); 65 assertNotNull(requestedChanges); 66 67 ConfigurationInternal toUpdate = getConfigurationInternal(userId); 68 69 // Simulate the real strategy's behavior: the new configuration will be updated to be the 70 // old configuration merged with the new if the user has the capability to update the 71 // settings. Then, if the configuration changed, the change listener is invoked. 72 TimeZoneCapabilities capabilities = toUpdate.asCapabilities(bypassUserPolicyChecks); 73 TimeZoneConfiguration configuration = toUpdate.asConfiguration(); 74 TimeZoneConfiguration newConfiguration = 75 capabilities.tryApplyConfigChanges(configuration, requestedChanges); 76 if (newConfiguration == null) { 77 return false; 78 } 79 80 if (!newConfiguration.equals(configuration)) { 81 ConfigurationInternal updatedConfiguration = toUpdate.merge(newConfiguration); 82 if (updatedConfiguration.getUserId() == mCurrentUserConfigurationInternal.getUserId()) { 83 mCurrentUserConfigurationInternal = updatedConfiguration; 84 } else if (mOtherUserConfigurationInternal != null 85 && updatedConfiguration.getUserId() 86 == mOtherUserConfigurationInternal.getUserId()) { 87 mOtherUserConfigurationInternal = updatedConfiguration; 88 } 89 // Note: Unlike the real strategy, the listeners are invoked synchronously. 90 notifyConfigurationChange(); 91 } 92 return true; 93 } 94 initializeCurrentUserConfiguration(ConfigurationInternal configurationInternal)95 void initializeCurrentUserConfiguration(ConfigurationInternal configurationInternal) { 96 mCurrentUserConfigurationInternal = configurationInternal; 97 } 98 initializeOtherUserConfiguration(ConfigurationInternal configurationInternal)99 void initializeOtherUserConfiguration(ConfigurationInternal configurationInternal) { 100 mOtherUserConfigurationInternal = configurationInternal; 101 } 102 simulateCurrentUserConfigurationInternalChange( ConfigurationInternal configurationInternal)103 void simulateCurrentUserConfigurationInternalChange( 104 ConfigurationInternal configurationInternal) { 105 mCurrentUserConfigurationInternal = configurationInternal; 106 // Note: Unlike the real strategy, the listeners are invoked synchronously. 107 notifyConfigurationChange(); 108 } 109 simulateOtherUserConfigurationInternalChange(ConfigurationInternal configurationInternal)110 void simulateOtherUserConfigurationInternalChange(ConfigurationInternal configurationInternal) { 111 mOtherUserConfigurationInternal = configurationInternal; 112 // Note: Unlike the real strategy, the listeners are invoked synchronously. 113 notifyConfigurationChange(); 114 } 115 116 @Override getConfigurationInternal(int userId)117 public ConfigurationInternal getConfigurationInternal(int userId) { 118 if (userId == mCurrentUserConfigurationInternal.getUserId()) { 119 return mCurrentUserConfigurationInternal; 120 } else if (mOtherUserConfigurationInternal != null 121 && userId == mOtherUserConfigurationInternal.getUserId()) { 122 return mOtherUserConfigurationInternal; 123 } 124 throw new AssertionError("userId not known: " + userId); 125 } 126 127 @Override addLocationTimeZoneManagerConfigListener(StateChangeListener listener)128 public void addLocationTimeZoneManagerConfigListener(StateChangeListener listener) { 129 failUnimplemented(); 130 } 131 132 @Override isTelephonyTimeZoneDetectionFeatureSupported()133 public boolean isTelephonyTimeZoneDetectionFeatureSupported() { 134 return failUnimplemented(); 135 } 136 137 @Override isGeoTimeZoneDetectionFeatureSupportedInConfig()138 public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() { 139 return failUnimplemented(); 140 } 141 142 @Override isGeoTimeZoneDetectionFeatureSupported()143 public boolean isGeoTimeZoneDetectionFeatureSupported() { 144 return failUnimplemented(); 145 } 146 147 @Override getPrimaryLocationTimeZoneProviderPackageName()148 public String getPrimaryLocationTimeZoneProviderPackageName() { 149 return failUnimplemented(); 150 } 151 152 @Override setTestPrimaryLocationTimeZoneProviderPackageName( String testPrimaryLocationTimeZoneProviderPackageName)153 public void setTestPrimaryLocationTimeZoneProviderPackageName( 154 String testPrimaryLocationTimeZoneProviderPackageName) { 155 failUnimplemented(); 156 } 157 158 @Override isTestPrimaryLocationTimeZoneProvider()159 public boolean isTestPrimaryLocationTimeZoneProvider() { 160 return failUnimplemented(); 161 } 162 163 @Override getSecondaryLocationTimeZoneProviderPackageName()164 public String getSecondaryLocationTimeZoneProviderPackageName() { 165 return failUnimplemented(); 166 } 167 168 @Override setTestSecondaryLocationTimeZoneProviderPackageName( String testSecondaryLocationTimeZoneProviderPackageName)169 public void setTestSecondaryLocationTimeZoneProviderPackageName( 170 String testSecondaryLocationTimeZoneProviderPackageName) { 171 failUnimplemented(); 172 } 173 174 @Override isTestSecondaryLocationTimeZoneProvider()175 public boolean isTestSecondaryLocationTimeZoneProvider() { 176 return failUnimplemented(); 177 } 178 179 @Override setRecordStateChangesForTests(boolean enabled)180 public void setRecordStateChangesForTests(boolean enabled) { 181 failUnimplemented(); 182 } 183 184 @Override getRecordStateChangesForTests()185 public boolean getRecordStateChangesForTests() { 186 return failUnimplemented(); 187 } 188 189 @Override getPrimaryLocationTimeZoneProviderMode()190 public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() { 191 return failUnimplemented(); 192 } 193 194 @Override getSecondaryLocationTimeZoneProviderMode()195 public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() { 196 return failUnimplemented(); 197 } 198 199 @Override isGeoDetectionEnabledForUsersByDefault()200 public boolean isGeoDetectionEnabledForUsersByDefault() { 201 return failUnimplemented(); 202 } 203 204 @Override getGeoDetectionSettingEnabledOverride()205 public Optional<Boolean> getGeoDetectionSettingEnabledOverride() { 206 return failUnimplemented(); 207 } 208 209 @Override getLocationTimeZoneProviderInitializationTimeout()210 public Duration getLocationTimeZoneProviderInitializationTimeout() { 211 return failUnimplemented(); 212 } 213 214 @Override getLocationTimeZoneProviderInitializationTimeoutFuzz()215 public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() { 216 return failUnimplemented(); 217 } 218 219 @Override getLocationTimeZoneUncertaintyDelay()220 public Duration getLocationTimeZoneUncertaintyDelay() { 221 return failUnimplemented(); 222 } 223 224 @Override getLocationTimeZoneProviderEventFilteringAgeThreshold()225 public Duration getLocationTimeZoneProviderEventFilteringAgeThreshold() { 226 return failUnimplemented(); 227 } 228 229 @Override resetVolatileTestConfig()230 public void resetVolatileTestConfig() { 231 failUnimplemented(); 232 } 233 notifyConfigurationChange()234 private void notifyConfigurationChange() { 235 for (StateChangeListener listener : mConfigurationInternalChangeListeners) { 236 listener.onChange(); 237 } 238 } 239 240 @SuppressWarnings("UnusedReturnValue") failUnimplemented()241 private static <T> T failUnimplemented() { 242 throw new AssertionError("Unimplemented"); 243 } 244 } 245