Merge "Add System APIs for TimeZoneProvider"
This commit is contained in:
@@ -9814,6 +9814,38 @@ package android.service.textclassifier {
|
||||
|
||||
}
|
||||
|
||||
package android.service.timezone {
|
||||
|
||||
public abstract class TimeZoneProviderService extends android.app.Service {
|
||||
ctor public TimeZoneProviderService();
|
||||
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method public abstract void onStartUpdates(long);
|
||||
method public abstract void onStopUpdates();
|
||||
method public final void reportPermanentFailure(@NonNull Throwable);
|
||||
method public final void reportSuggestion(@NonNull android.service.timezone.TimeZoneProviderSuggestion);
|
||||
method public final void reportUncertain();
|
||||
field public static final String BIND_PERMISSION = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
|
||||
field public static final String PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.PrimaryLocationTimeZoneProviderService";
|
||||
field public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.SecondaryLocationTimeZoneProviderService";
|
||||
}
|
||||
|
||||
public final class TimeZoneProviderSuggestion implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public long getElapsedRealtimeMillis();
|
||||
method @NonNull public java.util.List<java.lang.String> getTimeZoneIds();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.timezone.TimeZoneProviderSuggestion> CREATOR;
|
||||
}
|
||||
|
||||
public static final class TimeZoneProviderSuggestion.Builder {
|
||||
ctor public TimeZoneProviderSuggestion.Builder();
|
||||
method @NonNull public android.service.timezone.TimeZoneProviderSuggestion build();
|
||||
method @NonNull public android.service.timezone.TimeZoneProviderSuggestion.Builder setElapsedRealtimeMillis(long);
|
||||
method @NonNull public android.service.timezone.TimeZoneProviderSuggestion.Builder setTimeZoneIds(@NonNull java.util.List<java.lang.String>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.trust {
|
||||
|
||||
public class TrustAgentService extends android.app.Service {
|
||||
|
||||
28
core/java/android/service/timezone/ITimeZoneProvider.aidl
Normal file
28
core/java/android/service/timezone/ITimeZoneProvider.aidl
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
import android.service.timezone.ITimeZoneProviderManager;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ITimeZoneProvider {
|
||||
void setTimeZoneProviderManager(in @nullable ITimeZoneProviderManager manager);
|
||||
void startUpdates(in long initializationTimeoutMillis);
|
||||
void stopUpdates();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ITimeZoneProviderManager {
|
||||
void onTimeZoneProviderSuggestion(in TimeZoneProviderSuggestion timeZoneProviderSuggestion);
|
||||
void onTimeZoneProviderUncertain();
|
||||
void onTimeZoneProviderPermanentFailure(in String failureReason);
|
||||
}
|
||||
225
core/java/android/service/timezone/TimeZoneProviderService.java
Normal file
225
core/java/android/service/timezone/TimeZoneProviderService.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A service to generate time zone callbacks to the platform. Developers must extend this class.
|
||||
*
|
||||
* <p>Provider implementations are started via a call to {@link #onStartUpdates(long)} and stopped
|
||||
* via a call to {@link #onStopUpdates()}.
|
||||
*
|
||||
* <p>Once started, providers are expected to detect the time zone if possible, and report the
|
||||
* result via {@link #reportSuggestion(TimeZoneProviderSuggestion)} or {@link
|
||||
* #reportUncertain()}. Providers may also report that they have permanently failed
|
||||
* by calling {@link #reportPermanentFailure(Throwable)}. See the javadocs for each
|
||||
* method for details.
|
||||
*
|
||||
* <p>After starting, providers are expected to issue their first callback within the timeout
|
||||
* duration specified in {@link #onStartUpdates(long)}, or they will be implicitly considered to be
|
||||
* uncertain.
|
||||
*
|
||||
* <p>Once stopped or failed, providers are required to stop generating callbacks.
|
||||
*
|
||||
* <p>Provider discovery:
|
||||
*
|
||||
* <p>You must declare the service in your manifest file with the
|
||||
* {@link android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER} permission,
|
||||
* and include an intent filter with the necessary action indicating what type of provider it is.
|
||||
*
|
||||
* <p>Device configuration can influence how {@link TimeZoneProviderService}s are discovered.
|
||||
* In one mode, there can be multiple {@link TimeZoneProviderService}s configured with the same
|
||||
* action, and the one with the highest "serviceVersion" metadata will be used.
|
||||
*
|
||||
* <p>{@link TimeZoneProviderService}s may be deployed into processes that run once-per-user
|
||||
* or once-per-device (i.e. they service multiple users). The "serviceIsMultiuser" metadata must
|
||||
* be set accordingly.
|
||||
*
|
||||
* <p>Provider types:
|
||||
*
|
||||
* <p>Android currently supports up to two location-derived time zone providers. These are called
|
||||
* the "primary" and "secondary" location time zone provider, configured using {@link
|
||||
* #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
|
||||
* #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} respectively. The primary location time
|
||||
* zone provider is started first and will be used until becomes uncertain or fails, at which point
|
||||
* the secondary provider will be started.
|
||||
*
|
||||
* For example:
|
||||
* <pre>
|
||||
* <service android:name=".FooTimeZoneProviderService"
|
||||
* android:exported="true"
|
||||
* android:permission="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER">
|
||||
* <intent-filter>
|
||||
* <action
|
||||
* android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService"
|
||||
* />
|
||||
* </intent-filter>
|
||||
* <meta-data android:name="serviceVersion" android:value="1" />
|
||||
* <meta-data android:name="serviceIsMultiuser" android:value="true" />
|
||||
* </service>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>Threading:
|
||||
*
|
||||
* <p>Calls to {@code report} methods can be made on on any thread and will be passed asynchronously
|
||||
* to the system server. Calls to {@link #onStartUpdates(long)} and {@link #onStopUpdates()} will
|
||||
* occur on a single thread.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class TimeZoneProviderService extends Service {
|
||||
|
||||
private static final String TAG = "TimeZoneProviderService";
|
||||
|
||||
private final Handler mHandler = BackgroundThread.getHandler();
|
||||
|
||||
/**
|
||||
* The Intent action that the primary location-derived time zone provider service must respond
|
||||
* to. Add it to the intent filter of the service in its manifest.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE =
|
||||
"android.service.timezone.PrimaryLocationTimeZoneProviderService";
|
||||
|
||||
/**
|
||||
* The Intent action that the secondary location-based time zone provider service must respond
|
||||
* to. Add it to the intent filter of the service in its manifest.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE =
|
||||
"android.service.timezone.SecondaryLocationTimeZoneProviderService";
|
||||
|
||||
/**
|
||||
* The permission that a service must require to ensure that only Android system can bind to it.
|
||||
* If this permission is not enforced in the AndroidManifest of the service, the system will
|
||||
* skip that service.
|
||||
*/
|
||||
public static final String BIND_PERMISSION =
|
||||
"android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
|
||||
|
||||
private final TimeZoneProviderServiceWrapper mWrapper = new TimeZoneProviderServiceWrapper();
|
||||
|
||||
/** Set by {@link #mHandler} thread. */
|
||||
@Nullable
|
||||
private ITimeZoneProviderManager mManager;
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates a successful time zone detection. See {@link TimeZoneProviderSuggestion} for
|
||||
* details.
|
||||
*/
|
||||
public final void reportSuggestion(@NonNull TimeZoneProviderSuggestion suggestion) {
|
||||
Objects.requireNonNull(suggestion);
|
||||
|
||||
mHandler.post(() -> {
|
||||
ITimeZoneProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onTimeZoneProviderSuggestion(suggestion);
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the time zone is not known because of an expected runtime state or error, e.g. when
|
||||
* the provider is unable to detect location, or there was a problem when resolving the location
|
||||
* to a time zone.
|
||||
*/
|
||||
public final void reportUncertain() {
|
||||
mHandler.post(() -> {
|
||||
ITimeZoneProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onTimeZoneProviderUncertain();
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates there was a permanent failure. This is not generally expected, and probably means a
|
||||
* required backend service has been turned down, or the client is unreasonably old.
|
||||
*/
|
||||
public final void reportPermanentFailure(@NonNull Throwable cause) {
|
||||
Objects.requireNonNull(cause);
|
||||
|
||||
mHandler.post(() -> {
|
||||
ITimeZoneProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onTimeZoneProviderPermanentFailure(cause.getMessage());
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the provider sending updates.
|
||||
*/
|
||||
public abstract void onStartUpdates(@DurationMillisLong long initializationTimeoutMillis);
|
||||
|
||||
/**
|
||||
* Stops the provider sending updates.
|
||||
*/
|
||||
public abstract void onStopUpdates();
|
||||
|
||||
private class TimeZoneProviderServiceWrapper extends ITimeZoneProvider.Stub {
|
||||
|
||||
@Override
|
||||
public void setTimeZoneProviderManager(ITimeZoneProviderManager manager) {
|
||||
Objects.requireNonNull(manager);
|
||||
mHandler.post(() -> TimeZoneProviderService.this.mManager = manager);
|
||||
}
|
||||
|
||||
public void startUpdates(@DurationMillisLong long initializationTimeoutMillis) {
|
||||
mHandler.post(() -> onStartUpdates(initializationTimeoutMillis));
|
||||
}
|
||||
|
||||
public void stopUpdates() {
|
||||
mHandler.post(TimeZoneProviderService.this::onStopUpdates);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
parcelable TimeZoneProviderSuggestion;
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A suggestion from a {@link TimeZoneProviderService} containing zero or more time zones.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class TimeZoneProviderSuggestion implements Parcelable {
|
||||
|
||||
@NonNull
|
||||
private final List<String> mTimeZoneIds;
|
||||
|
||||
@ElapsedRealtimeLong
|
||||
private final long mElapsedRealtimeMillis;
|
||||
|
||||
private TimeZoneProviderSuggestion(@NonNull List<String> timeZoneIds,
|
||||
@ElapsedRealtimeLong long elapsedRealtimeMillis) {
|
||||
mTimeZoneIds = immutableList(timeZoneIds);
|
||||
mElapsedRealtimeMillis = elapsedRealtimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time of the suggestion in elapsed real-time since system boot. Where possible,
|
||||
* the time should be based on the time of the data used when determining time zone. For
|
||||
* example, if it was based on a {@link android.location.Location} then it should be the time
|
||||
* associated with that location.
|
||||
*
|
||||
* <p>This value is compared to {@link
|
||||
* android.os.SystemClock#elapsedRealtime()}, to calculate the age of a fix and to compare
|
||||
* {@link TimeZoneProviderSuggestion} instances.
|
||||
*
|
||||
* @return elapsed real-time of fix, in milliseconds
|
||||
*/
|
||||
@ElapsedRealtimeLong
|
||||
public long getElapsedRealtimeMillis() {
|
||||
return mElapsedRealtimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zero or more time zone IDs for this suggestion.
|
||||
*
|
||||
* <p>Time zone IDs are TZDB IDs like "America/Los_Angeles" that would be accepted by {@link
|
||||
* java.util.TimeZone#getTimeZone(String)}.
|
||||
*
|
||||
* <p>Most often a suggestion will contain a single time zone ID but other possibilities are
|
||||
* valid. A suggestion with zero time zone IDs means the provider is certain there are no time
|
||||
* zones for the current location, e.g. for oceans, boundaries or disputed areas. A suggestion
|
||||
* with multiple IDs can occur on boundaries or disputed areas. The ordering should be in order
|
||||
* of likelihood if possible, but the time zone detection service may choose from any of the
|
||||
* zones suggested if it has other supporting information available.
|
||||
*/
|
||||
@NonNull
|
||||
public List<String> getTimeZoneIds() {
|
||||
return mTimeZoneIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneProviderSuggestion{"
|
||||
+ "mTimeZoneIds=" + mTimeZoneIds
|
||||
+ ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
|
||||
+ "(" + Duration.ofMillis(mElapsedRealtimeMillis) + ")"
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<TimeZoneProviderSuggestion> CREATOR =
|
||||
new Creator<TimeZoneProviderSuggestion>() {
|
||||
@Override
|
||||
public TimeZoneProviderSuggestion createFromParcel(Parcel in) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<String> timeZoneIds =
|
||||
(ArrayList<String>) in.readArrayList(null /* classLoader */);
|
||||
long elapsedRealtimeMillis = in.readLong();
|
||||
return new TimeZoneProviderSuggestion(timeZoneIds, elapsedRealtimeMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneProviderSuggestion[] newArray(int size) {
|
||||
return new TimeZoneProviderSuggestion[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||
parcel.writeList(mTimeZoneIds);
|
||||
parcel.writeLong(mElapsedRealtimeMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TimeZoneProviderSuggestion that = (TimeZoneProviderSuggestion) o;
|
||||
return mElapsedRealtimeMillis == that.mElapsedRealtimeMillis
|
||||
&& mTimeZoneIds.equals(that.mTimeZoneIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mTimeZoneIds, mElapsedRealtimeMillis);
|
||||
}
|
||||
|
||||
/** A builder for {@link TimeZoneProviderSuggestion}. */
|
||||
public static final class Builder {
|
||||
|
||||
private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
|
||||
@ElapsedRealtimeLong
|
||||
private long mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
|
||||
|
||||
/**
|
||||
* Sets the time zone IDs of this suggestion.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) {
|
||||
mTimeZoneIds = Objects.requireNonNull(timeZoneIds);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time of this suggestion, in elapsed real-time since system boot.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setElapsedRealtimeMillis(@ElapsedRealtimeLong long time) {
|
||||
mElapsedRealtimeMillis = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link TimeZoneProviderSuggestion} instance.
|
||||
*/
|
||||
@NonNull
|
||||
public TimeZoneProviderSuggestion build() {
|
||||
return new TimeZoneProviderSuggestion(mTimeZoneIds, mElapsedRealtimeMillis);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static List<String> immutableList(@NonNull List<String> list) {
|
||||
Objects.requireNonNull(list);
|
||||
if (list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Collections.unmodifiableList(new ArrayList<>(list));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5304,7 +5304,7 @@
|
||||
<attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
|
||||
<!-- Attribution for the Offline LocationTimeZoneProvider, used to detect time zone using
|
||||
on-device data -->
|
||||
<attribution android:tag="OfflineLocationTimeZoneProvider"
|
||||
<attribution android:tag="OfflineLocationTimeZoneProviderService"
|
||||
android:label="@string/offline_location_time_zone_detection_service_attribution"/>
|
||||
|
||||
<application android:process="system"
|
||||
@@ -5774,11 +5774,10 @@
|
||||
|
||||
<!-- AOSP configures a default secondary LocationTimeZoneProvider that uses an on-device
|
||||
data set from the com.android.geotz APEX. -->
|
||||
<uses-library android:name="com.android.location.provider" />
|
||||
<service android:name="com.android.timezone.geotz.provider.OfflineLocationTimeZoneService"
|
||||
<service android:name="com.android.timezone.geotz.provider.OfflineLocationTimeZoneProviderService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider" />
|
||||
<action android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="serviceVersion" android:value="1" />
|
||||
<meta-data android:name="serviceIsMultiuser" android:value="true" />
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.timezone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/** Utility methods related to {@link Parcelable} objects used in several tests. */
|
||||
final class ParcelableTestSupport {
|
||||
|
||||
private ParcelableTestSupport() {}
|
||||
|
||||
/** Returns the result of parceling and unparceling the argument. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Parcelable> T roundTripParcelable(T parcelable) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parcel.writeTypedObject(parcelable, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
Parcelable.Creator<T> creator;
|
||||
try {
|
||||
Field creatorField = parcelable.getClass().getField("CREATOR");
|
||||
creator = (Parcelable.Creator<T>) creatorField.get(null);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
T toReturn = parcel.readTypedObject(creator);
|
||||
parcel.recycle();
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static <T extends Parcelable> void assertRoundTripParcelable(T instance) {
|
||||
assertEquals(instance, roundTripParcelable(instance));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.service.timezone;
|
||||
|
||||
import static android.service.timezone.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TimeZoneProviderSuggestionTest {
|
||||
|
||||
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 9999;
|
||||
|
||||
private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testInvalidTimeZoneIds() {
|
||||
new TimeZoneProviderSuggestion.Builder()
|
||||
.setTimeZoneIds(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TimeZoneProviderSuggestion.Builder builder1 = new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
assertEquals(one, one);
|
||||
}
|
||||
|
||||
TimeZoneProviderSuggestion.Builder builder2 = new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
TimeZoneProviderSuggestion two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
assertEquals(two, one);
|
||||
}
|
||||
|
||||
builder1.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
TimeZoneProviderSuggestion two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
assertNotEquals(two, one);
|
||||
}
|
||||
|
||||
builder2.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
TimeZoneProviderSuggestion two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
assertEquals(two, one);
|
||||
}
|
||||
|
||||
builder2.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
TimeZoneProviderSuggestion two = builder2.build();
|
||||
assertNotEquals(one, two);
|
||||
assertNotEquals(two, one);
|
||||
}
|
||||
|
||||
builder1.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
|
||||
{
|
||||
TimeZoneProviderSuggestion one = builder1.build();
|
||||
TimeZoneProviderSuggestion two = builder2.build();
|
||||
assertEquals(one, two);
|
||||
assertEquals(two, one);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable_noTimeZoneIds() {
|
||||
TimeZoneProviderSuggestion.Builder builder = new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable_withTimeZoneIds() {
|
||||
TimeZoneProviderSuggestion.Builder builder = new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
|
||||
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
|
||||
assertRoundTripParcelable(builder.build());
|
||||
}
|
||||
}
|
||||
@@ -17,20 +17,17 @@
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -57,9 +54,9 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
void onInitialize() {
|
||||
mProxy.initialize(new LocationTimeZoneProviderProxy.Listener() {
|
||||
@Override
|
||||
public void onReportLocationTimeZoneEvent(
|
||||
@NonNull LocationTimeZoneEvent locationTimeZoneEvent) {
|
||||
handleLocationTimeZoneEvent(locationTimeZoneEvent);
|
||||
public void onReportTimeZoneProviderEvent(
|
||||
@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
|
||||
handleTimeZoneProviderEvent(timeZoneProviderEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,27 +77,27 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
synchronized (mSharedLock) {
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
switch (currentState.stateEnum) {
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN: {
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN: {
|
||||
// Losing a remote provider is treated as becoming uncertain.
|
||||
String msg = "handleProviderLost reason=" + reason
|
||||
+ ", mProviderName=" + mProviderName
|
||||
+ ", currentState=" + currentState;
|
||||
debugLog(msg);
|
||||
// This is an unusual PROVIDER_STATE_ENABLED_UNCERTAIN state because
|
||||
// This is an unusual PROVIDER_STATE_STARTED_UNCERTAIN state because
|
||||
// event == null
|
||||
ProviderState newState = currentState.newState(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, null,
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, null,
|
||||
currentState.currentUserConfiguration, msg);
|
||||
setCurrentState(newState, true);
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
debugLog("handleProviderLost reason=" + reason
|
||||
+ ", mProviderName=" + mProviderName
|
||||
+ ", currentState=" + currentState
|
||||
+ ": No state change required, provider is disabled.");
|
||||
+ ": No state change required, provider is stopped.");
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
@@ -123,16 +120,16 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
synchronized (mSharedLock) {
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
switch (currentState.stateEnum) {
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
debugLog("handleOnProviderBound mProviderName=" + mProviderName
|
||||
+ ", currentState=" + currentState + ": Provider is enabled.");
|
||||
+ ", currentState=" + currentState + ": Provider is started.");
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
debugLog("handleOnProviderBound mProviderName=" + mProviderName
|
||||
+ ", currentState=" + currentState + ": Provider is disabled.");
|
||||
+ ", currentState=" + currentState + ": Provider is stopped.");
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
@@ -150,23 +147,17 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onEnable(@NonNull Duration initializationTimeout) {
|
||||
void onStartUpdates(@NonNull Duration initializationTimeout) {
|
||||
// Set a request on the proxy - it will be sent immediately if the service is bound,
|
||||
// or will be sent as soon as the service becomes bound.
|
||||
LocationTimeZoneProviderRequest request =
|
||||
new LocationTimeZoneProviderRequest.Builder()
|
||||
.setReportLocationTimeZone(true)
|
||||
.setInitializationTimeoutMillis(initializationTimeout.toMillis())
|
||||
.build();
|
||||
TimeZoneProviderRequest request =
|
||||
TimeZoneProviderRequest.createStartUpdatesRequest(initializationTimeout);
|
||||
mProxy.setRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDisable() {
|
||||
LocationTimeZoneProviderRequest request =
|
||||
new LocationTimeZoneProviderRequest.Builder()
|
||||
.setReportLocationTimeZone(false)
|
||||
.build();
|
||||
void onStopUpdates() {
|
||||
TimeZoneProviderRequest request = TimeZoneProviderRequest.createStopUpdatesRequest();
|
||||
mProxy.setRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,24 +16,24 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_SUGGESTION;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
|
||||
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue;
|
||||
import com.android.server.timezonedetector.ConfigurationInternal;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
@@ -46,9 +46,9 @@ import java.util.Objects;
|
||||
* A real implementation of {@link LocationTimeZoneProviderController} that supports a primary and a
|
||||
* secondary {@link LocationTimeZoneProvider}.
|
||||
*
|
||||
* <p>The primary is used until it fails or becomes uncertain. The secondary will then be enabled.
|
||||
* <p>The primary is used until it fails or becomes uncertain. The secondary will then be started.
|
||||
* The controller will immediately make suggestions based on "certain" {@link
|
||||
* LocationTimeZoneEvent}s, i.e. events that demonstrate the provider is certain what the time zone
|
||||
* TimeZoneProviderEvent}s, i.e. events that demonstrate the provider is certain what the time zone
|
||||
* is. The controller will not make immediate suggestions based on "uncertain" events, giving
|
||||
* providers time to change their mind. This also gives the secondary provider time to initialize
|
||||
* when the primary becomes uncertain.
|
||||
@@ -107,7 +107,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
mPrimaryProvider.initialize(providerListener);
|
||||
mSecondaryProvider.initialize(providerListener);
|
||||
|
||||
alterProvidersEnabledStateIfRequired(
|
||||
alterProvidersStartedStateIfRequired(
|
||||
null /* oldConfiguration */, mCurrentUserConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -125,15 +125,15 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
|
||||
if (!newConfig.equals(oldConfig)) {
|
||||
if (newConfig.getUserId() != oldConfig.getUserId()) {
|
||||
// If the user changed, disable the providers if needed. They may be re-enabled
|
||||
// If the user changed, stop the providers if needed. They may be re-started
|
||||
// for the new user immediately afterwards if their settings allow.
|
||||
debugLog("User changed. old=" + oldConfig.getUserId()
|
||||
+ ", new=" + newConfig.getUserId() + ": Disabling providers");
|
||||
disableProviders();
|
||||
+ ", new=" + newConfig.getUserId() + ": Stopping providers");
|
||||
stopProviders();
|
||||
|
||||
alterProvidersEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
|
||||
alterProvidersStartedStateIfRequired(null /* oldConfiguration */, newConfig);
|
||||
} else {
|
||||
alterProvidersEnabledStateIfRequired(oldConfig, newConfig);
|
||||
alterProvidersStartedStateIfRequired(oldConfig, newConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,43 +145,44 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
@Override
|
||||
@DurationMillisLong
|
||||
long getUncertaintyTimeoutDelayMillis() {
|
||||
return mUncertaintyTimeoutQueue.getQueuedDelayMillis();
|
||||
}
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
private void disableProviders() {
|
||||
disableProviderIfEnabled(mPrimaryProvider);
|
||||
disableProviderIfEnabled(mSecondaryProvider);
|
||||
private void stopProviders() {
|
||||
stopProviderIfStarted(mPrimaryProvider);
|
||||
stopProviderIfStarted(mSecondaryProvider);
|
||||
|
||||
// By definition, if both providers are disabled, the controller is uncertain.
|
||||
// By definition, if both providers are stopped, the controller is uncertain.
|
||||
cancelUncertaintyTimeout();
|
||||
}
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
private void disableProviderIfEnabled(@NonNull LocationTimeZoneProvider provider) {
|
||||
if (provider.getCurrentState().isEnabled()) {
|
||||
disableProvider(provider);
|
||||
private void stopProviderIfStarted(@NonNull LocationTimeZoneProvider provider) {
|
||||
if (provider.getCurrentState().isStarted()) {
|
||||
stopProvider(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
private void disableProvider(@NonNull LocationTimeZoneProvider provider) {
|
||||
private void stopProvider(@NonNull LocationTimeZoneProvider provider) {
|
||||
ProviderState providerState = provider.getCurrentState();
|
||||
switch (providerState.stateEnum) {
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
debugLog("No need to disable " + provider + ": already disabled");
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
debugLog("No need to stop " + provider + ": already stopped");
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
debugLog("Disabling " + provider);
|
||||
provider.disable();
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
debugLog("Stopping " + provider);
|
||||
provider.stopUpdates();
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
debugLog("Unable to disable " + provider + ": it is perm failed");
|
||||
debugLog("Unable to stop " + provider + ": it is perm failed");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -192,20 +193,20 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the providers into the correct enabled/disabled state for the {@code newConfiguration}
|
||||
* Sets the providers into the correct started/stopped state for the {@code newConfiguration}
|
||||
* and, if there is a provider state change, makes any suggestions required to inform the
|
||||
* downstream time zone detection code.
|
||||
*
|
||||
* <p>This is a utility method that exists to avoid duplicated logic for the various cases when
|
||||
* provider enabled / disabled state may need to be set or changed, e.g. during initialization
|
||||
* provider started / stopped state may need to be set or changed, e.g. during initialization
|
||||
* or when a new configuration has been received.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void alterProvidersEnabledStateIfRequired(
|
||||
private void alterProvidersStartedStateIfRequired(
|
||||
@Nullable ConfigurationInternal oldConfiguration,
|
||||
@NonNull ConfigurationInternal newConfiguration) {
|
||||
|
||||
// Provider enabled / disabled states only need to be changed if geoDetectionEnabled has
|
||||
// Provider started / stopped states only need to be changed if geoDetectionEnabled has
|
||||
// changed.
|
||||
boolean oldGeoDetectionEnabled = oldConfiguration != null
|
||||
&& oldConfiguration.getGeoDetectionEnabledBehavior();
|
||||
@@ -215,28 +216,28 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
// The check above ensures that the logic below only executes if providers are going from
|
||||
// {enabled *} -> {disabled}, or {disabled} -> {enabled initializing}. If this changes in
|
||||
// future and there could be {enabled *} -> {enabled *} cases, or cases where the provider
|
||||
// can't be assumed to go straight to the {enabled initializing} state, then the logic below
|
||||
// {started *} -> {stopped}, or {stopped} -> {started initializing}. If this changes in
|
||||
// future and there could be {started *} -> {started *} cases, or cases where the provider
|
||||
// can't be assumed to go straight to the {started initializing} state, then the logic below
|
||||
// would need to cover extra conditions, for example:
|
||||
// 1) If the primary is in {enabled uncertain}, the secondary should be enabled.
|
||||
// 1) If the primary is in {started uncertain}, the secondary should be started.
|
||||
// 2) If (1), and the secondary instantly enters the {perm failed} state, the uncertainty
|
||||
// timeout started when the primary entered {enabled uncertain} should be cancelled.
|
||||
// timeout started when the primary entered {started uncertain} should be cancelled.
|
||||
|
||||
if (newGeoDetectionEnabled) {
|
||||
// Try to enable the primary provider.
|
||||
tryEnableProvider(mPrimaryProvider, newConfiguration);
|
||||
// Try to start the primary provider.
|
||||
tryStartProvider(mPrimaryProvider, newConfiguration);
|
||||
|
||||
// The secondary should only ever be enabled if the primary now isn't enabled (i.e. it
|
||||
// couldn't become {enabled initializing} because it is {perm failed}).
|
||||
// The secondary should only ever be started if the primary now isn't started (i.e. it
|
||||
// couldn't become {started initializing} because it is {perm failed}).
|
||||
ProviderState newPrimaryState = mPrimaryProvider.getCurrentState();
|
||||
if (!newPrimaryState.isEnabled()) {
|
||||
// If the primary provider is {perm failed} then the controller must try to enable
|
||||
if (!newPrimaryState.isStarted()) {
|
||||
// If the primary provider is {perm failed} then the controller must try to start
|
||||
// the secondary.
|
||||
tryEnableProvider(mSecondaryProvider, newConfiguration);
|
||||
tryStartProvider(mSecondaryProvider, newConfiguration);
|
||||
|
||||
ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
|
||||
if (!newSecondaryState.isEnabled()) {
|
||||
if (!newSecondaryState.isStarted()) {
|
||||
// If both providers are {perm failed} then the controller immediately
|
||||
// becomes uncertain.
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
@@ -247,7 +248,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
disableProviders();
|
||||
stopProviders();
|
||||
|
||||
// There can be an uncertainty timeout set if the controller most recently received
|
||||
// an uncertain event. This is a no-op if there isn't a timeout set.
|
||||
@@ -256,34 +257,35 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
// If a previous "certain" suggestion has been made, then a new "uncertain"
|
||||
// suggestion must now be made to indicate the controller {does not / no longer has}
|
||||
// an opinion and will not be sending further updates (until at least the config
|
||||
// changes again and providers are re-enabled).
|
||||
// changes again and providers are re-started).
|
||||
if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
"Provider is disabled:"
|
||||
"Provider is stopped:"
|
||||
+ " primary=" + mPrimaryProvider.getCurrentState());
|
||||
makeSuggestion(suggestion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tryEnableProvider(@NonNull LocationTimeZoneProvider provider,
|
||||
private void tryStartProvider(@NonNull LocationTimeZoneProvider provider,
|
||||
@NonNull ConfigurationInternal configuration) {
|
||||
ProviderState providerState = provider.getCurrentState();
|
||||
switch (providerState.stateEnum) {
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
debugLog("Enabling " + provider);
|
||||
provider.enable(configuration, mEnvironment.getProviderInitializationTimeout(),
|
||||
provider.startUpdates(configuration,
|
||||
mEnvironment.getProviderInitializationTimeout(),
|
||||
mEnvironment.getProviderInitializationTimeoutFuzz());
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
debugLog("No need to enable " + provider + ": already enabled");
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
debugLog("No need to start " + provider + ": already started");
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
debugLog("Unable to enable " + provider + ": it is perm failed");
|
||||
debugLog("Unable to start " + provider + ": it is perm failed");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -300,20 +302,20 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
switch (providerState.stateEnum) {
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
// This should never happen: entering disabled does not trigger a state change.
|
||||
warnLog("onProviderStateChange: Unexpected state change for disabled provider,"
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
// This should never happen: entering stopped does not trigger a state change.
|
||||
warnLog("onProviderStateChange: Unexpected state change for stopped provider,"
|
||||
+ " provider=" + provider);
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
// Entering enabled does not trigger a state change, so this only happens if an
|
||||
// event is received while the provider is enabled.
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
// Entering started does not trigger a state change, so this only happens if an
|
||||
// event is received while the provider is started.
|
||||
debugLog("onProviderStateChange: Received notification of a state change while"
|
||||
+ " enabled, provider=" + provider);
|
||||
handleProviderEnabledStateChange(providerState);
|
||||
+ " started, provider=" + provider);
|
||||
handleProviderStartedStateChange(providerState);
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
@@ -344,18 +346,18 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
ProviderState primaryCurrentState = mPrimaryProvider.getCurrentState();
|
||||
ProviderState secondaryCurrentState = mSecondaryProvider.getCurrentState();
|
||||
|
||||
// If a provider has failed, the other may need to be enabled.
|
||||
// If a provider has failed, the other may need to be started.
|
||||
if (failedProvider == mPrimaryProvider) {
|
||||
if (secondaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
|
||||
// The primary must have failed. Try to enable the secondary. This does nothing if
|
||||
// the provider is already enabled, and will leave the provider in
|
||||
// {enabled initializing} if the provider is disabled.
|
||||
tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
|
||||
// The primary must have failed. Try to start the secondary. This does nothing if
|
||||
// the provider is already started, and will leave the provider in
|
||||
// {started initializing} if the provider is stopped.
|
||||
tryStartProvider(mSecondaryProvider, mCurrentUserConfiguration);
|
||||
}
|
||||
} else if (failedProvider == mSecondaryProvider) {
|
||||
// No-op: The secondary will only be active if the primary is uncertain or is failed.
|
||||
// So, there the primary should not need to be enabled when the secondary fails.
|
||||
if (primaryCurrentState.stateEnum != PROVIDER_STATE_ENABLED_UNCERTAIN
|
||||
// So, there the primary should not need to be started when the secondary fails.
|
||||
if (primaryCurrentState.stateEnum != PROVIDER_STATE_STARTED_UNCERTAIN
|
||||
&& primaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
|
||||
warnLog("Secondary provider unexpected reported a failure:"
|
||||
+ " failed provider=" + failedProvider.getName()
|
||||
@@ -384,16 +386,16 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a provider has changed state but just moved from one enabled state to another
|
||||
* enabled state, usually as a result of a new {@link LocationTimeZoneEvent} being received.
|
||||
* Called when a provider has changed state but just moved from one started state to another
|
||||
* started state, usually as a result of a new {@link TimeZoneProviderEvent} being received.
|
||||
* However, there are rare cases where the event can also be null.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void handleProviderEnabledStateChange(@NonNull ProviderState providerState) {
|
||||
private void handleProviderStartedStateChange(@NonNull ProviderState providerState) {
|
||||
LocationTimeZoneProvider provider = providerState.provider;
|
||||
LocationTimeZoneEvent event = providerState.event;
|
||||
TimeZoneProviderEvent event = providerState.event;
|
||||
if (event == null) {
|
||||
// Implicit uncertainty, i.e. where the provider is enabled, but a problem has been
|
||||
// Implicit uncertainty, i.e. where the provider is started, but a problem has been
|
||||
// detected without having received an event. For example, if the process has detected
|
||||
// the loss of a binder-based provider, or initialization took too long. This is treated
|
||||
// the same as explicit uncertainty, i.e. where the provider has explicitly told this
|
||||
@@ -404,18 +406,18 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
if (!mCurrentUserConfiguration.getGeoDetectionEnabledBehavior()) {
|
||||
// This should not happen: the provider should not be in an enabled state if the user
|
||||
// This should not happen: the provider should not be in an started state if the user
|
||||
// does not have geodetection enabled.
|
||||
warnLog("Provider=" + provider + " is enabled, but"
|
||||
warnLog("Provider=" + provider + " is started, but"
|
||||
+ " currentUserConfiguration=" + mCurrentUserConfiguration
|
||||
+ " suggests it shouldn't be.");
|
||||
}
|
||||
|
||||
switch (event.getEventType()) {
|
||||
switch (event.getType()) {
|
||||
case EVENT_TYPE_PERMANENT_FAILURE: {
|
||||
// This shouldn't happen. A provider cannot be enabled and have this event type.
|
||||
// This shouldn't happen. A provider cannot be started and have this event type.
|
||||
warnLog("Provider=" + provider
|
||||
+ " is enabled, but event suggests it shouldn't be");
|
||||
+ " is started, but event suggests it shouldn't be");
|
||||
break;
|
||||
}
|
||||
case EVENT_TYPE_UNCERTAIN: {
|
||||
@@ -423,13 +425,13 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
+ ", explicit uncertainty. event=" + event);
|
||||
break;
|
||||
}
|
||||
case EVENT_TYPE_SUCCESS: {
|
||||
handleProviderCertainty(provider, event.getTimeZoneIds(),
|
||||
case EVENT_TYPE_SUGGESTION: {
|
||||
handleProviderSuggestion(provider, event.getSuggestion().getTimeZoneIds(),
|
||||
"Event received provider=" + provider + ", event=" + event);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
warnLog("Unknown eventType=" + event.getEventType());
|
||||
warnLog("Unknown eventType=" + event.getType());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -439,7 +441,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
* Called when a provider has become "certain" about the time zone(s).
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void handleProviderCertainty(
|
||||
private void handleProviderSuggestion(
|
||||
@NonNull LocationTimeZoneProvider provider,
|
||||
@Nullable List<String> timeZoneIds,
|
||||
@NonNull String reason) {
|
||||
@@ -447,11 +449,10 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
cancelUncertaintyTimeout();
|
||||
|
||||
if (provider == mPrimaryProvider) {
|
||||
disableProviderIfEnabled(mSecondaryProvider);
|
||||
stopProviderIfStarted(mSecondaryProvider);
|
||||
}
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
new GeolocationTimeZoneSuggestion(timeZoneIds);
|
||||
GeolocationTimeZoneSuggestion suggestion = new GeolocationTimeZoneSuggestion(timeZoneIds);
|
||||
suggestion.addDebugInfo(reason);
|
||||
// Rely on the receiver to dedupe suggestions. It is better to over-communicate.
|
||||
makeSuggestion(suggestion);
|
||||
@@ -503,7 +504,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
* Called when a provider has become "uncertain" about the time zone.
|
||||
*
|
||||
* <p>A provider is expected to report its uncertainty as soon as it becomes uncertain, as
|
||||
* this enables the most flexibility for the controller to enable other providers when there are
|
||||
* this enables the most flexibility for the controller to start other providers when there are
|
||||
* multiple ones available. The controller is therefore responsible for deciding when to make a
|
||||
* "uncertain" suggestion to the downstream time zone detector.
|
||||
*
|
||||
@@ -532,11 +533,11 @@ class ControllerImpl extends LocationTimeZoneProviderController {
|
||||
}
|
||||
|
||||
if (provider == mPrimaryProvider) {
|
||||
// (Try to) enable the secondary. It could already be enabled, or enabling might not
|
||||
// (Try to) start the secondary. It could already be started, or enabling might not
|
||||
// succeed if the provider has previously reported it is perm failed. The uncertainty
|
||||
// timeout (set above) is used to ensure that an uncertain suggestion will be made if
|
||||
// the secondary cannot generate a success event in time.
|
||||
tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
|
||||
tryStartProvider(mSecondaryProvider, mCurrentUserConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
|
||||
@@ -57,12 +58,12 @@ final class HandlerThreadingDomain extends ThreadingDomain {
|
||||
}
|
||||
|
||||
@Override
|
||||
void postDelayed(@NonNull Runnable r, long delayMillis) {
|
||||
void postDelayed(@NonNull Runnable r, @DurationMillisLong long delayMillis) {
|
||||
getHandler().postDelayed(r, delayMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
void postDelayed(Runnable r, Object token, long delayMillis) {
|
||||
void postDelayed(Runnable r, Object token, @DurationMillisLong long delayMillis) {
|
||||
getHandler().postDelayed(r, token, delayMillis);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.os.Binder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.SystemProperties;
|
||||
import android.service.timezone.TimeZoneProviderService;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -44,7 +45,7 @@ import java.util.Objects;
|
||||
* A service class that acts as a container for the {@link LocationTimeZoneProviderController},
|
||||
* which determines what {@link com.android.server.timezonedetector.GeolocationTimeZoneSuggestion}
|
||||
* are made to the {@link TimeZoneDetectorInternal}, and the {@link LocationTimeZoneProvider}s that
|
||||
* (indirectly) generate {@link com.android.internal.location.timezone.LocationTimeZoneEvent}s.
|
||||
* (indirectly) generate {@link TimeZoneProviderEvent}s.
|
||||
*
|
||||
* <p>For details of the time zone suggestion behavior, see {@link
|
||||
* LocationTimeZoneProviderController}.
|
||||
@@ -120,9 +121,9 @@ public class LocationTimeZoneManagerService extends Binder {
|
||||
private static final String ATTRIBUTION_TAG = "LocationTimeZoneService";
|
||||
|
||||
private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
|
||||
"com.android.location.timezone.service.v1.PrimaryLocationTimeZoneProvider";
|
||||
TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
|
||||
private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
|
||||
"com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider";
|
||||
TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
|
||||
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_SUGGESTION;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
|
||||
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -34,7 +35,6 @@ import android.os.SystemClock;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
|
||||
import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue;
|
||||
import com.android.server.timezonedetector.ConfigurationInternal;
|
||||
@@ -50,7 +50,7 @@ import java.util.Objects;
|
||||
* process, or could be a stubbed instance when no real provider is registered.
|
||||
*
|
||||
* <p>The provider is supplied with a {@link ProviderListener} via {@link
|
||||
* #initialize(ProviderListener)}. This enables it to communicates asynchronous detection / error
|
||||
* #initialize(ProviderListener)}. This starts communication of asynchronous detection / error
|
||||
* events back to the {@link LocationTimeZoneProviderController} via the {@link
|
||||
* ProviderListener#onProviderStateChange} method. This call must be made on the
|
||||
* {@link Handler} thread from the {@link ThreadingDomain} passed to the constructor.
|
||||
@@ -77,9 +77,10 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
*/
|
||||
static class ProviderState {
|
||||
|
||||
@IntDef({ PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_ENABLED_INITIALIZING,
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, PROVIDER_STATE_ENABLED_UNCERTAIN,
|
||||
PROVIDER_STATE_DISABLED, PROVIDER_STATE_PERM_FAILED })
|
||||
@IntDef(prefix = "PROVIDER_STATE_",
|
||||
value = { PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_STARTED_INITIALIZING,
|
||||
PROVIDER_STATE_STARTED_CERTAIN, PROVIDER_STATE_STARTED_UNCERTAIN,
|
||||
PROVIDER_STATE_STOPPED, PROVIDER_STATE_PERM_FAILED })
|
||||
@interface ProviderStateEnum {}
|
||||
|
||||
/**
|
||||
@@ -88,31 +89,31 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
static final int PROVIDER_STATE_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* The provider is enabled and has not reported its first event.
|
||||
* The provider is started and has not reported its first event.
|
||||
*/
|
||||
static final int PROVIDER_STATE_ENABLED_INITIALIZING = 1;
|
||||
static final int PROVIDER_STATE_STARTED_INITIALIZING = 1;
|
||||
|
||||
/**
|
||||
* The provider is enabled and most recently reported a "success" event.
|
||||
* The provider is started and most recently reported a "suggestion" event.
|
||||
*/
|
||||
static final int PROVIDER_STATE_ENABLED_CERTAIN = 2;
|
||||
static final int PROVIDER_STATE_STARTED_CERTAIN = 2;
|
||||
|
||||
/**
|
||||
* The provider is enabled and most recently reported an "uncertain" event.
|
||||
* The provider is started and most recently reported an "uncertain" event.
|
||||
*/
|
||||
static final int PROVIDER_STATE_ENABLED_UNCERTAIN = 3;
|
||||
static final int PROVIDER_STATE_STARTED_UNCERTAIN = 3;
|
||||
|
||||
/**
|
||||
* The provider is disabled.
|
||||
* The provider is stopped.
|
||||
*
|
||||
* This is the state after {@link #initialize} is called.
|
||||
*/
|
||||
static final int PROVIDER_STATE_DISABLED = 4;
|
||||
static final int PROVIDER_STATE_STOPPED = 4;
|
||||
|
||||
/**
|
||||
* The provider has failed and cannot be re-enabled.
|
||||
* The provider has failed and cannot be re-started.
|
||||
*
|
||||
* Providers may enter this state after a provider is enabled.
|
||||
* Providers may enter this state after a provider is started.
|
||||
*/
|
||||
static final int PROVIDER_STATE_PERM_FAILED = 5;
|
||||
|
||||
@@ -123,16 +124,16 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
public final @ProviderStateEnum int stateEnum;
|
||||
|
||||
/**
|
||||
* The last {@link LocationTimeZoneEvent} received. Only populated when {@link #stateEnum}
|
||||
* is either {@link #PROVIDER_STATE_ENABLED_CERTAIN} or {@link
|
||||
* #PROVIDER_STATE_ENABLED_UNCERTAIN}, but it can be {@code null} then too if no event has
|
||||
* The last {@link TimeZoneProviderEvent} received. Only populated when {@link #stateEnum}
|
||||
* is either {@link #PROVIDER_STATE_STARTED_CERTAIN} or {@link
|
||||
* #PROVIDER_STATE_STARTED_UNCERTAIN}, but it can be {@code null} then too if no event has
|
||||
* yet been received.
|
||||
*/
|
||||
@Nullable public final LocationTimeZoneEvent event;
|
||||
@Nullable public final TimeZoneProviderEvent event;
|
||||
|
||||
/**
|
||||
* The user configuration associated with the current state. Only and always present when
|
||||
* {@link #stateEnum} is one of the enabled states.
|
||||
* {@link #stateEnum} is one of the started states.
|
||||
*/
|
||||
@Nullable public final ConfigurationInternal currentUserConfiguration;
|
||||
|
||||
@@ -140,6 +141,7 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
* The time according to the elapsed realtime clock when the provider entered the current
|
||||
* state. Included for debugging, not used for equality.
|
||||
*/
|
||||
@ElapsedRealtimeLong
|
||||
private final long mStateEntryTimeMillis;
|
||||
|
||||
/**
|
||||
@@ -151,7 +153,7 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
|
||||
private ProviderState(@NonNull LocationTimeZoneProvider provider,
|
||||
@ProviderStateEnum int stateEnum,
|
||||
@Nullable LocationTimeZoneEvent event,
|
||||
@Nullable TimeZoneProviderEvent event,
|
||||
@Nullable ConfigurationInternal currentUserConfiguration,
|
||||
@Nullable String debugInfo) {
|
||||
this.provider = Objects.requireNonNull(provider);
|
||||
@@ -174,25 +176,25 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
* and that the required parameters for the new state are present / absent.
|
||||
*/
|
||||
ProviderState newState(@ProviderStateEnum int newStateEnum,
|
||||
@Nullable LocationTimeZoneEvent event,
|
||||
@Nullable TimeZoneProviderEvent event,
|
||||
@Nullable ConfigurationInternal currentUserConfig,
|
||||
@Nullable String debugInfo) {
|
||||
|
||||
// Check valid "from" transitions.
|
||||
switch (this.stateEnum) {
|
||||
case PROVIDER_STATE_UNKNOWN: {
|
||||
if (newStateEnum != PROVIDER_STATE_DISABLED) {
|
||||
if (newStateEnum != PROVIDER_STATE_STOPPED) {
|
||||
throw new IllegalArgumentException(
|
||||
"Must transition from " + prettyPrintStateEnum(
|
||||
PROVIDER_STATE_UNKNOWN)
|
||||
+ " to " + prettyPrintStateEnum(PROVIDER_STATE_DISABLED));
|
||||
+ " to " + prettyPrintStateEnum(PROVIDER_STATE_STOPPED));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_DISABLED:
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
case PROVIDER_STATE_STOPPED:
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
// These can go to each other or PROVIDER_STATE_PERM_FAILED.
|
||||
break;
|
||||
}
|
||||
@@ -211,21 +213,21 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
throw new IllegalArgumentException("Cannot transition to "
|
||||
+ prettyPrintStateEnum(PROVIDER_STATE_UNKNOWN));
|
||||
}
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
if (event != null || currentUserConfig != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Disabled state: event and currentUserConfig must be null"
|
||||
"Stopped state: event and currentUserConfig must be null"
|
||||
+ ", event=" + event
|
||||
+ ", currentUserConfig=" + currentUserConfig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
if (currentUserConfig == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Enabled state: currentUserConfig must not be null");
|
||||
"Started state: currentUserConfig must not be null");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -245,11 +247,11 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
return new ProviderState(provider, newStateEnum, event, currentUserConfig, debugInfo);
|
||||
}
|
||||
|
||||
/** Returns {@code true} if {@link #stateEnum} is one of the enabled states. */
|
||||
boolean isEnabled() {
|
||||
return stateEnum == PROVIDER_STATE_ENABLED_INITIALIZING
|
||||
|| stateEnum == PROVIDER_STATE_ENABLED_CERTAIN
|
||||
|| stateEnum == PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
/** Returns {@code true} if {@link #stateEnum} is one of the started states. */
|
||||
boolean isStarted() {
|
||||
return stateEnum == PROVIDER_STATE_STARTED_INITIALIZING
|
||||
|| stateEnum == PROVIDER_STATE_STARTED_CERTAIN
|
||||
|| stateEnum == PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -286,14 +288,14 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
|
||||
private static String prettyPrintStateEnum(@ProviderStateEnum int state) {
|
||||
switch (state) {
|
||||
case PROVIDER_STATE_DISABLED:
|
||||
return "Disabled (" + PROVIDER_STATE_DISABLED + ")";
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
return "Enabled initializing (" + PROVIDER_STATE_ENABLED_INITIALIZING + ")";
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
return "Enabled certain (" + PROVIDER_STATE_ENABLED_CERTAIN + ")";
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN:
|
||||
return "Enabled uncertain (" + PROVIDER_STATE_ENABLED_UNCERTAIN + ")";
|
||||
case PROVIDER_STATE_STOPPED:
|
||||
return "Stopped (" + PROVIDER_STATE_STOPPED + ")";
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
return "Started initializing (" + PROVIDER_STATE_STARTED_INITIALIZING + ")";
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
return "Started certain (" + PROVIDER_STATE_STARTED_CERTAIN + ")";
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN:
|
||||
return "Started uncertain (" + PROVIDER_STATE_STARTED_UNCERTAIN + ")";
|
||||
case PROVIDER_STATE_PERM_FAILED:
|
||||
return "Perm failure (" + PROVIDER_STATE_PERM_FAILED + ")";
|
||||
case PROVIDER_STATE_UNKNOWN:
|
||||
@@ -315,7 +317,7 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
new ReferenceWithHistory<>(10);
|
||||
|
||||
/**
|
||||
* Used for scheduling initialization timeouts, i.e. for providers that have just been enabled.
|
||||
* Used for scheduling initialization timeouts, i.e. for providers that have just been started.
|
||||
*/
|
||||
@NonNull private final SingleRunnableQueue mInitializationTimeoutQueue;
|
||||
|
||||
@@ -344,7 +346,7 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
mProviderListener = Objects.requireNonNull(providerListener);
|
||||
ProviderState currentState = ProviderState.createStartingState(this);
|
||||
ProviderState newState = currentState.newState(
|
||||
PROVIDER_STATE_DISABLED, null, null,
|
||||
PROVIDER_STATE_STOPPED, null, null,
|
||||
"initialize() called");
|
||||
setCurrentState(newState, false);
|
||||
|
||||
@@ -407,28 +409,28 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the provider. It is an error to call this method except when the {@link
|
||||
* #getCurrentState()} is at {@link ProviderState#PROVIDER_STATE_DISABLED}. This method must be
|
||||
* Starts the provider. It is an error to call this method except when the {@link
|
||||
* #getCurrentState()} is at {@link ProviderState#PROVIDER_STATE_STOPPED}. This method must be
|
||||
* called using the handler thread from the {@link ThreadingDomain}.
|
||||
*/
|
||||
final void enable(@NonNull ConfigurationInternal currentUserConfiguration,
|
||||
final void startUpdates(@NonNull ConfigurationInternal currentUserConfiguration,
|
||||
@NonNull Duration initializationTimeout, @NonNull Duration initializationTimeoutFuzz) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
assertCurrentState(PROVIDER_STATE_DISABLED);
|
||||
assertCurrentState(PROVIDER_STATE_STOPPED);
|
||||
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
ProviderState newState = currentState.newState(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, null /* event */,
|
||||
currentUserConfiguration, "enable() called");
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, null /* event */,
|
||||
currentUserConfiguration, "startUpdates() called");
|
||||
setCurrentState(newState, false);
|
||||
|
||||
Duration delay = initializationTimeout.plus(initializationTimeoutFuzz);
|
||||
mInitializationTimeoutQueue.runDelayed(
|
||||
this::handleInitializationTimeout, delay.toMillis());
|
||||
|
||||
onEnable(initializationTimeout);
|
||||
onStartUpdates(initializationTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,10 +439,10 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
if (currentState.stateEnum == PROVIDER_STATE_ENABLED_INITIALIZING) {
|
||||
if (currentState.stateEnum == PROVIDER_STATE_STARTED_INITIALIZING) {
|
||||
// On initialization timeout the provider becomes uncertain.
|
||||
ProviderState newState = currentState.newState(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, null /* event */,
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, null /* event */,
|
||||
currentState.currentUserConfiguration, "initialization timeout");
|
||||
setCurrentState(newState, true);
|
||||
}
|
||||
@@ -448,65 +450,64 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented by subclasses to do work during {@link #enable}.
|
||||
* Implemented by subclasses to do work during {@link #startUpdates}.
|
||||
*/
|
||||
abstract void onEnable(@NonNull Duration initializationTimeout);
|
||||
abstract void onStartUpdates(@NonNull Duration initializationTimeout);
|
||||
|
||||
/**
|
||||
* Disables the provider. It is an error* to call this method except when the {@link
|
||||
* #getCurrentState()} is one of the enabled states. This method must be
|
||||
* Stops the provider. It is an error* to call this method except when the {@link
|
||||
* #getCurrentState()} is one of the started states. This method must be
|
||||
* called using the handler thread from the {@link ThreadingDomain}.
|
||||
*/
|
||||
final void disable() {
|
||||
final void stopUpdates() {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
assertIsEnabled();
|
||||
assertIsStarted();
|
||||
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
ProviderState newState = currentState.newState(
|
||||
PROVIDER_STATE_DISABLED, null, null, "disable() called");
|
||||
PROVIDER_STATE_STOPPED, null, null, "stopUpdates() called");
|
||||
setCurrentState(newState, false);
|
||||
|
||||
if (mInitializationTimeoutQueue.hasQueued()) {
|
||||
mInitializationTimeoutQueue.cancel();
|
||||
}
|
||||
|
||||
onDisable();
|
||||
onStopUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented by subclasses to do work during {@link #disable}.
|
||||
* Implemented by subclasses to do work during {@link #stopUpdates}.
|
||||
*/
|
||||
abstract void onDisable();
|
||||
abstract void onStopUpdates();
|
||||
|
||||
/** For subclasses to invoke when a {@link LocationTimeZoneEvent} has been received. */
|
||||
final void handleLocationTimeZoneEvent(
|
||||
@NonNull LocationTimeZoneEvent locationTimeZoneEvent) {
|
||||
/** For subclasses to invoke when a {@link TimeZoneProviderEvent} has been received. */
|
||||
final void handleTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
Objects.requireNonNull(locationTimeZoneEvent);
|
||||
Objects.requireNonNull(timeZoneProviderEvent);
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
debugLog("handleLocationTimeZoneEvent: mProviderName=" + mProviderName
|
||||
+ ", locationTimeZoneEvent=" + locationTimeZoneEvent);
|
||||
debugLog("handleTimeZoneProviderEvent: mProviderName=" + mProviderName
|
||||
+ ", timeZoneProviderEvent=" + timeZoneProviderEvent);
|
||||
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
int eventType = locationTimeZoneEvent.getEventType();
|
||||
int eventType = timeZoneProviderEvent.getType();
|
||||
switch (currentState.stateEnum) {
|
||||
case PROVIDER_STATE_PERM_FAILED: {
|
||||
// After entering perm failed, there is nothing to do. The remote peer is
|
||||
// supposed to stop sending events after it has reported perm failure.
|
||||
logWarn("handleLocationTimeZoneEvent: Event=" + locationTimeZoneEvent
|
||||
logWarn("handleTimeZoneProviderEvent: Event=" + timeZoneProviderEvent
|
||||
+ " received for provider=" + this + " when in failed state");
|
||||
return;
|
||||
}
|
||||
case PROVIDER_STATE_DISABLED: {
|
||||
case PROVIDER_STATE_STOPPED: {
|
||||
switch (eventType) {
|
||||
case EVENT_TYPE_PERMANENT_FAILURE: {
|
||||
String msg = "handleLocationTimeZoneEvent:"
|
||||
+ " Failure event=" + locationTimeZoneEvent
|
||||
+ " received for disabled provider=" + this
|
||||
String msg = "handleTimeZoneProviderEvent:"
|
||||
+ " Failure event=" + timeZoneProviderEvent
|
||||
+ " received for stopped provider=" + this
|
||||
+ ", entering permanently failed state";
|
||||
logWarn(msg);
|
||||
ProviderState newState = currentState.newState(
|
||||
@@ -517,30 +518,30 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case EVENT_TYPE_SUCCESS:
|
||||
case EVENT_TYPE_SUGGESTION:
|
||||
case EVENT_TYPE_UNCERTAIN: {
|
||||
// Any geolocation-related events received for a disabled provider are
|
||||
// Any geolocation-related events received for a stopped provider are
|
||||
// ignored: they should not happen.
|
||||
logWarn("handleLocationTimeZoneEvent:"
|
||||
+ " event=" + locationTimeZoneEvent
|
||||
+ " received for disabled provider=" + this
|
||||
logWarn("handleTimeZoneProviderEvent:"
|
||||
+ " event=" + timeZoneProviderEvent
|
||||
+ " received for stopped provider=" + this
|
||||
+ ", ignoring");
|
||||
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException(
|
||||
"Unknown eventType=" + locationTimeZoneEvent);
|
||||
"Unknown eventType=" + timeZoneProviderEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
case PROVIDER_STATE_ENABLED_INITIALIZING:
|
||||
case PROVIDER_STATE_ENABLED_CERTAIN:
|
||||
case PROVIDER_STATE_ENABLED_UNCERTAIN: {
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN: {
|
||||
switch (eventType) {
|
||||
case EVENT_TYPE_PERMANENT_FAILURE: {
|
||||
String msg = "handleLocationTimeZoneEvent:"
|
||||
+ " Failure event=" + locationTimeZoneEvent
|
||||
String msg = "handleTimeZoneProviderEvent:"
|
||||
+ " Failure event=" + timeZoneProviderEvent
|
||||
+ " received for provider=" + this
|
||||
+ ", entering permanently failed state";
|
||||
logWarn(msg);
|
||||
@@ -554,16 +555,16 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
return;
|
||||
}
|
||||
case EVENT_TYPE_UNCERTAIN:
|
||||
case EVENT_TYPE_SUCCESS: {
|
||||
case EVENT_TYPE_SUGGESTION: {
|
||||
@ProviderStateEnum int providerStateEnum;
|
||||
if (eventType == EVENT_TYPE_UNCERTAIN) {
|
||||
providerStateEnum = PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
providerStateEnum = PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
} else {
|
||||
providerStateEnum = PROVIDER_STATE_ENABLED_CERTAIN;
|
||||
providerStateEnum = PROVIDER_STATE_STARTED_CERTAIN;
|
||||
}
|
||||
ProviderState newState = currentState.newState(providerStateEnum,
|
||||
locationTimeZoneEvent, currentState.currentUserConfiguration,
|
||||
"handleLocationTimeZoneEvent() when enabled");
|
||||
timeZoneProviderEvent, currentState.currentUserConfiguration,
|
||||
"handleTimeZoneProviderEvent() when started");
|
||||
setCurrentState(newState, true);
|
||||
if (mInitializationTimeoutQueue.hasQueued()) {
|
||||
mInitializationTimeoutQueue.cancel();
|
||||
@@ -572,7 +573,7 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException(
|
||||
"Unknown eventType=" + locationTimeZoneEvent);
|
||||
"Unknown eventType=" + timeZoneProviderEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -589,10 +590,10 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
abstract void logWarn(String msg);
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
private void assertIsEnabled() {
|
||||
private void assertIsStarted() {
|
||||
ProviderState currentState = mCurrentState.get();
|
||||
if (!currentState.isEnabled()) {
|
||||
throw new IllegalStateException("Required an enabled state, but was " + currentState);
|
||||
if (!currentState.isStarted()) {
|
||||
throw new IllegalStateException("Required a started state, but was " + currentState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
|
||||
@@ -59,7 +60,7 @@ import java.util.Objects;
|
||||
* disputed areas and oceans. Distinguishing uncertainty allows the controller to try other
|
||||
* providers (or give up), where as certainty means it should not.
|
||||
*
|
||||
* <p>A provider can fail permanently. A permanent failure will disable the provider until next
|
||||
* <p>A provider can fail permanently. A permanent failure will stop the provider until next
|
||||
* boot.
|
||||
*/
|
||||
abstract class LocationTimeZoneProviderController implements Dumpable {
|
||||
@@ -90,6 +91,7 @@ abstract class LocationTimeZoneProviderController implements Dumpable {
|
||||
abstract boolean isUncertaintyTimeoutSet();
|
||||
|
||||
@VisibleForTesting
|
||||
@DurationMillisLong
|
||||
abstract long getUncertaintyTimeoutDelayMillis();
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,17 +23,15 @@ import android.os.Handler;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
|
||||
import com.android.server.timezonedetector.Dumpable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* System server-side proxy for ILocationTimeZoneProvider implementations, i.e. this provides the
|
||||
* system server object used to communicate with a remote LocationTimeZoneProvider over Binder,
|
||||
* which could be running in a different process. As LocationTimeZoneProviders are bound / unbound
|
||||
* this proxy will rebind to the "best" available remote process.
|
||||
* System server-side proxy for ITimeZoneProvider implementations, i.e. this provides the system
|
||||
* server object used to communicate with a remote TimeZoneProvider over Binder, which could be
|
||||
* running in a different process. As TimeZoneProviders are bound / unbound this proxy will rebind
|
||||
* to the "best" available remote process.
|
||||
*
|
||||
* <p>Threading guarantees provided / required by this interface:
|
||||
* <ul>
|
||||
@@ -41,8 +39,8 @@ import java.util.Objects;
|
||||
* from the {@link ThreadingDomain} passed to the constructor, excluding
|
||||
* {@link #dump(IndentingPrintWriter, String[])}</li>
|
||||
* <li>Non-static public methods that make binder calls to remote processes (e.g.
|
||||
* {@link #setRequest(LocationTimeZoneProviderRequest)}) are executed asynchronously and will
|
||||
* return immediately.</li>
|
||||
* {@link #setRequest(TimeZoneProviderRequest)}) are executed asynchronously and will return
|
||||
* immediately.</li>
|
||||
* <li>Callbacks received via binder are delivered via {@link Listener} are delivered on the
|
||||
* {@link Handler} thread from the {@link ThreadingDomain} passed to the constructor.
|
||||
* </ul>
|
||||
@@ -93,16 +91,15 @@ abstract class LocationTimeZoneProviderProxy implements Dumpable {
|
||||
/**
|
||||
* Sets a new request for the provider.
|
||||
*/
|
||||
abstract void setRequest(@NonNull LocationTimeZoneProviderRequest request);
|
||||
abstract void setRequest(@NonNull TimeZoneProviderRequest request);
|
||||
|
||||
/**
|
||||
* Handles a {@link LocationTimeZoneEvent} from a remote process.
|
||||
* Handles a {@link TimeZoneProviderEvent} from a remote process.
|
||||
*/
|
||||
final void handleLocationTimeZoneEvent(
|
||||
@NonNull LocationTimeZoneEvent locationTimeZoneEvent) {
|
||||
final void handleTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
|
||||
// These calls are invoked on a binder thread. Move to the mThreadingDomain thread as
|
||||
// required by the guarantees for this class.
|
||||
mThreadingDomain.post(() -> mListener.onReportLocationTimeZoneEvent(locationTimeZoneEvent));
|
||||
mThreadingDomain.post(() -> mListener.onReportTimeZoneProviderEvent(timeZoneProviderEvent));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,9 +109,9 @@ abstract class LocationTimeZoneProviderProxy implements Dumpable {
|
||||
interface Listener {
|
||||
|
||||
/**
|
||||
* Called when a provider receives a {@link LocationTimeZoneEvent}.
|
||||
* Called when a provider receives a {@link TimeZoneProviderEvent}.
|
||||
*/
|
||||
void onReportLocationTimeZoneEvent(@NonNull LocationTimeZoneEvent locationTimeZoneEvent);
|
||||
void onReportTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent);
|
||||
|
||||
/**
|
||||
* Called when a provider is (re)bound.
|
||||
|
||||
@@ -35,11 +35,11 @@ import java.time.Duration;
|
||||
* and a secondary {@link LocationTimeZoneProvider}, but only a primary is configured, the secondary
|
||||
* config will be left null and the {@link LocationTimeZoneProvider} implementation will be
|
||||
* defaulted to a {@link NullLocationTimeZoneProvider}. The {@link NullLocationTimeZoneProvider}
|
||||
* enters a {@link ProviderState#PROVIDER_STATE_PERM_FAILED} state immediately after being enabled
|
||||
* enters a {@link ProviderState#PROVIDER_STATE_PERM_FAILED} state immediately after being started
|
||||
* for the first time and sends the appropriate event, which ensures the {@link
|
||||
* LocationTimeZoneProviderController} won't expect any further {@link
|
||||
* com.android.internal.location.timezone.LocationTimeZoneEvent}s to come from it, and won't attempt
|
||||
* to use it again.
|
||||
* TimeZoneProviderEvent}s to come from it, and won't attempt to use it
|
||||
* again.
|
||||
*/
|
||||
class NullLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
|
||||
@@ -57,7 +57,7 @@ class NullLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onEnable(@NonNull Duration initializationTimeout) {
|
||||
void onStartUpdates(@NonNull Duration initializationTimeout) {
|
||||
// Report a failure (asynchronously using the mThreadingDomain thread to avoid recursion).
|
||||
mThreadingDomain.post(()-> {
|
||||
// Enter the perm-failed state.
|
||||
@@ -69,8 +69,8 @@ class NullLocationTimeZoneProvider extends LocationTimeZoneProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDisable() {
|
||||
// Ignored - NullLocationTimeZoneProvider is always permanently failed.
|
||||
void onStopUpdates() {
|
||||
// Ignored - this implementation is always permanently failed.
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,22 +22,22 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.service.timezone.ITimeZoneProvider;
|
||||
import android.service.timezone.ITimeZoneProviderManager;
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.location.timezone.ILocationTimeZoneProvider;
|
||||
import com.android.internal.location.timezone.ILocationTimeZoneProviderManager;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
|
||||
import com.android.server.ServiceWatcher;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* System server-side proxy for ILocationTimeZoneProvider implementations, i.e. this provides the
|
||||
* system server object used to communicate with a remote LocationTimeZoneProvider over Binder,
|
||||
* which could be running in a different process. As "remote" LocationTimeZoneProviders are bound /
|
||||
* unbound this proxy will rebind to the "best" available remote process.
|
||||
* System server-side proxy for ITimeZoneProvider implementations, i.e. this provides the
|
||||
* system server object used to communicate with a remote {@link
|
||||
* android.service.timezone.TimeZoneProviderService} over Binder, which could be running in a
|
||||
* different process. As "remote" providers are bound / unbound this proxy will rebind to the "best"
|
||||
* available remote process.
|
||||
*/
|
||||
class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
|
||||
@@ -47,7 +47,7 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
@Nullable private ManagerProxy mManagerProxy;
|
||||
|
||||
@GuardedBy("mProxyLock")
|
||||
@NonNull private LocationTimeZoneProviderRequest mRequest;
|
||||
@NonNull private TimeZoneProviderRequest mRequest;
|
||||
|
||||
RealLocationTimeZoneProviderProxy(
|
||||
@NonNull Context context, @NonNull ThreadingDomain threadingDomain,
|
||||
@@ -55,7 +55,7 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
int nonOverlayPackageResId) {
|
||||
super(context, threadingDomain);
|
||||
mManagerProxy = null;
|
||||
mRequest = LocationTimeZoneProviderRequest.EMPTY_REQUEST;
|
||||
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
|
||||
mServiceWatcher = new ServiceWatcher(context, action, this::onBind, this::onUnbind,
|
||||
enableOverlayResId, nonOverlayPackageResId);
|
||||
}
|
||||
@@ -93,12 +93,12 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
private void onBindOnHandlerThread(@NonNull IBinder binder) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
ILocationTimeZoneProvider provider = ILocationTimeZoneProvider.Stub.asInterface(binder);
|
||||
ITimeZoneProvider provider = ITimeZoneProvider.Stub.asInterface(binder);
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
try {
|
||||
mManagerProxy = new ManagerProxy();
|
||||
provider.setLocationTimeZoneProviderManager(mManagerProxy);
|
||||
provider.setTimeZoneProviderManager(mManagerProxy);
|
||||
trySendCurrentRequest();
|
||||
mListener.onProviderBound();
|
||||
} catch (RemoteException e) {
|
||||
@@ -118,7 +118,7 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
}
|
||||
|
||||
@Override
|
||||
final void setRequest(@NonNull LocationTimeZoneProviderRequest request) {
|
||||
final void setRequest(@NonNull TimeZoneProviderRequest request) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
Objects.requireNonNull(request);
|
||||
@@ -131,11 +131,14 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
|
||||
@GuardedBy("mProxyLock")
|
||||
private void trySendCurrentRequest() {
|
||||
LocationTimeZoneProviderRequest request = mRequest;
|
||||
TimeZoneProviderRequest request = mRequest;
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationTimeZoneProvider service =
|
||||
ILocationTimeZoneProvider.Stub.asInterface(binder);
|
||||
service.setRequest(request);
|
||||
ITimeZoneProvider service = ITimeZoneProvider.Stub.asInterface(binder);
|
||||
if (request.sendUpdates()) {
|
||||
service.startUpdates(request.getInitializationTimeout().toMillis());
|
||||
} else {
|
||||
service.stopUpdates();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -148,21 +151,39 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
}
|
||||
|
||||
/**
|
||||
* A system Server-side proxy for the ILocationTimeZoneProviderManager, i.e. this is a local
|
||||
* binder stub. Each "remote" LocationTimeZoneProvider is passed a binder instance that it
|
||||
* then uses to communicate back with the system server, invoking the logic here.
|
||||
* A system Server-side proxy for the ITimeZoneProviderManager, i.e. this is a local binder stub
|
||||
* Each "remote" TimeZoneProvider is passed a binder instance that it then uses to communicate
|
||||
* back with the system server, invoking the logic here.
|
||||
*/
|
||||
private class ManagerProxy extends ILocationTimeZoneProviderManager.Stub {
|
||||
private class ManagerProxy extends ITimeZoneProviderManager.Stub {
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onLocationTimeZoneEvent(LocationTimeZoneEvent locationTimeZoneEvent) {
|
||||
public void onTimeZoneProviderSuggestion(TimeZoneProviderSuggestion suggestion) {
|
||||
onTimeZoneProviderEvent(TimeZoneProviderEvent.createSuggestionEvent(suggestion));
|
||||
}
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onTimeZoneProviderUncertain() {
|
||||
onTimeZoneProviderEvent(TimeZoneProviderEvent.createUncertainEvent());
|
||||
|
||||
}
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onTimeZoneProviderPermanentFailure(String failureReason) {
|
||||
onTimeZoneProviderEvent(
|
||||
TimeZoneProviderEvent.createPermanentFailureEvent(failureReason));
|
||||
}
|
||||
|
||||
private void onTimeZoneProviderEvent(TimeZoneProviderEvent event) {
|
||||
synchronized (mSharedLock) {
|
||||
if (mManagerProxy != this) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
handleLocationTimeZoneEvent(locationTimeZoneEvent);
|
||||
handleTimeZoneProviderEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.PRIMARY_PROVIDER_NAME;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.SECONDARY_PROVIDER_NAME;
|
||||
|
||||
@@ -26,8 +23,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -50,14 +46,14 @@ final class SimulatedBinderProviderEvent {
|
||||
|
||||
|
||||
@NonNull private final String mProviderName;
|
||||
private final int mEventType;
|
||||
@Nullable private final LocationTimeZoneEvent mLocationTimeZoneEvent;
|
||||
private final int mType;
|
||||
@Nullable private final TimeZoneProviderEvent mTimeZoneProviderEvent;
|
||||
|
||||
private SimulatedBinderProviderEvent(@NonNull String providerName, int eventType,
|
||||
@Nullable LocationTimeZoneEvent locationTimeZoneEvent) {
|
||||
@Nullable TimeZoneProviderEvent timeZoneProviderEvent) {
|
||||
this.mProviderName = Objects.requireNonNull(providerName);
|
||||
this.mEventType = eventType;
|
||||
this.mLocationTimeZoneEvent = locationTimeZoneEvent;
|
||||
this.mType = eventType;
|
||||
this.mTimeZoneProviderEvent = timeZoneProviderEvent;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -66,24 +62,24 @@ final class SimulatedBinderProviderEvent {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
LocationTimeZoneEvent getLocationTimeZoneEvent() {
|
||||
return mLocationTimeZoneEvent;
|
||||
TimeZoneProviderEvent getTimeZoneProviderEvent() {
|
||||
return mTimeZoneProviderEvent;
|
||||
}
|
||||
|
||||
int getEventType() {
|
||||
return mEventType;
|
||||
int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/** Prints the command line options that {@link #createFromArgs(ShellCommand)} understands. */
|
||||
static void printCommandLineOpts(PrintWriter pw) {
|
||||
pw.println("Simulated provider binder event:");
|
||||
pw.println();
|
||||
pw.println("<provider name> [onBind|onUnbind|locationTimeZoneEvent"
|
||||
pw.println("<provider name> [onBind|onUnbind|timeZoneProviderEvent"
|
||||
+ " <location time zone event args>]");
|
||||
pw.println();
|
||||
pw.println("<provider name> = " + VALID_PROVIDER_NAMES);
|
||||
pw.println("<location time zone event args> ="
|
||||
+ " [PERMANENT_FAILURE|UNCERTAIN|SUCCESS <time zone ids>*]");
|
||||
pw.println("<time zone provider event args> ="
|
||||
+ " [PERMANENT_FAILURE|UNCERTAIN|SUGGESTION <time zone ids>*]");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +100,8 @@ final class SimulatedBinderProviderEvent {
|
||||
return new SimulatedBinderProviderEvent(
|
||||
providerName, INJECTED_EVENT_TYPE_ON_UNBIND, null);
|
||||
}
|
||||
case "locationTimeZoneEvent": {
|
||||
LocationTimeZoneEvent event = parseLocationTimeZoneEventArgs(shellCommand);
|
||||
case "timeZoneProviderEvent": {
|
||||
TimeZoneProviderEvent event = parseTimeZoneProviderEventArgs(shellCommand);
|
||||
return new SimulatedBinderProviderEvent(providerName,
|
||||
INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT, event);
|
||||
}
|
||||
@@ -115,30 +111,31 @@ final class SimulatedBinderProviderEvent {
|
||||
}
|
||||
}
|
||||
|
||||
private static LocationTimeZoneEvent parseLocationTimeZoneEventArgs(ShellCommand shellCommand) {
|
||||
LocationTimeZoneEvent.Builder eventBuilder = new LocationTimeZoneEvent.Builder()
|
||||
.setElapsedRealtimeMillis(SystemClock.elapsedRealtime());
|
||||
|
||||
private static TimeZoneProviderEvent parseTimeZoneProviderEventArgs(ShellCommand shellCommand) {
|
||||
TimeZoneProviderEvent event;
|
||||
String eventTypeString = shellCommand.getNextArgRequired();
|
||||
switch (eventTypeString.toUpperCase()) {
|
||||
case "PERMANENT_FAILURE": {
|
||||
eventBuilder.setEventType(EVENT_TYPE_PERMANENT_FAILURE);
|
||||
event = TimeZoneProviderEvent.createPermanentFailureEvent("Simulated");
|
||||
break;
|
||||
}
|
||||
case "UNCERTAIN": {
|
||||
eventBuilder.setEventType(EVENT_TYPE_UNCERTAIN);
|
||||
event = TimeZoneProviderEvent.createUncertainEvent();
|
||||
break;
|
||||
}
|
||||
case "SUCCESS": {
|
||||
eventBuilder.setEventType(EVENT_TYPE_SUCCESS)
|
||||
.setTimeZoneIds(parseTimeZoneArgs(shellCommand));
|
||||
case "SUGGESTION": {
|
||||
TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(SystemClock.elapsedRealtime())
|
||||
.setTimeZoneIds(parseTimeZoneArgs(shellCommand))
|
||||
.build();
|
||||
event = TimeZoneProviderEvent.createSuggestionEvent(suggestion);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Error: Unknown eventType: " + eventTypeString);
|
||||
}
|
||||
}
|
||||
return eventBuilder.build();
|
||||
return event;
|
||||
}
|
||||
|
||||
private static List<String> parseTimeZoneArgs(ShellCommand shellCommand) {
|
||||
@@ -154,8 +151,8 @@ final class SimulatedBinderProviderEvent {
|
||||
public String toString() {
|
||||
return "SimulatedBinderProviderEvent{"
|
||||
+ "mProviderName=" + mProviderName
|
||||
+ ", mEventType=" + mEventType
|
||||
+ ", mLocationTimeZoneEvent=" + mLocationTimeZoneEvent
|
||||
+ ", mType=" + mType
|
||||
+ ", mTimeZoneProviderEvent=" + mTimeZoneProviderEvent
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.content.Context;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
|
||||
import com.android.server.timezonedetector.ReferenceWithHistory;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -38,7 +37,7 @@ import java.util.Objects;
|
||||
class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
@NonNull private LocationTimeZoneProviderRequest mRequest;
|
||||
@NonNull private TimeZoneProviderRequest mRequest;
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
@NonNull private final ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
|
||||
@@ -46,7 +45,7 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
|
||||
SimulatedLocationTimeZoneProviderProxy(
|
||||
@NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
|
||||
super(context, threadingDomain);
|
||||
mRequest = LocationTimeZoneProviderRequest.EMPTY_REQUEST;
|
||||
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,7 +59,7 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
|
||||
Objects.requireNonNull(event);
|
||||
|
||||
synchronized (mSharedLock) {
|
||||
switch (event.getEventType()) {
|
||||
switch (event.getType()) {
|
||||
case INJECTED_EVENT_TYPE_ON_BIND: {
|
||||
mLastEvent.set("Simulating onProviderBound(), event=" + event);
|
||||
mThreadingDomain.post(this::onBindOnHandlerThread);
|
||||
@@ -72,12 +71,12 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
|
||||
break;
|
||||
}
|
||||
case INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT: {
|
||||
if (!mRequest.getReportLocationTimeZone()) {
|
||||
if (!mRequest.sendUpdates()) {
|
||||
mLastEvent.set("Test event=" + event + " is testing an invalid case:"
|
||||
+ " reporting is off. mRequest=" + mRequest);
|
||||
}
|
||||
mLastEvent.set("Simulating LocationTimeZoneEvent, event=" + event);
|
||||
handleLocationTimeZoneEvent(event.getLocationTimeZoneEvent());
|
||||
mLastEvent.set("Simulating TimeZoneProviderResult, event=" + event);
|
||||
handleTimeZoneProviderEvent(event.getTimeZoneProviderEvent());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -106,7 +105,7 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
|
||||
}
|
||||
|
||||
@Override
|
||||
final void setRequest(@NonNull LocationTimeZoneProviderRequest request) {
|
||||
final void setRequest(@NonNull TimeZoneProviderRequest request) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
Objects.requireNonNull(request);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import android.annotation.DurationMillisLong;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -68,9 +69,9 @@ abstract class ThreadingDomain {
|
||||
/**
|
||||
* Execute the supplied runnable on the threading domain's thread with a delay.
|
||||
*/
|
||||
abstract void postDelayed(@NonNull Runnable runnable, long delayMillis);
|
||||
abstract void postDelayed(@NonNull Runnable runnable, @DurationMillisLong long delayMillis);
|
||||
|
||||
abstract void postDelayed(Runnable r, Object token, long delayMillis);
|
||||
abstract void postDelayed(Runnable r, Object token, @DurationMillisLong long delayMillis);
|
||||
|
||||
abstract void removeQueuedRunnables(Object token);
|
||||
|
||||
@@ -90,6 +91,7 @@ abstract class ThreadingDomain {
|
||||
final class SingleRunnableQueue {
|
||||
|
||||
private boolean mIsQueued;
|
||||
@DurationMillisLong
|
||||
private long mDelayMillis;
|
||||
|
||||
/**
|
||||
@@ -97,7 +99,7 @@ abstract class ThreadingDomain {
|
||||
* handler thread, cancelling any queued but not-yet-executed {@link Runnable} previously
|
||||
* added by this. This method must be called from the threading domain's thread.
|
||||
*/
|
||||
void runDelayed(Runnable r, long delayMillis) {
|
||||
void runDelayed(Runnable r, @DurationMillisLong long delayMillis) {
|
||||
cancel();
|
||||
mIsQueued = true;
|
||||
mDelayMillis = delayMillis;
|
||||
@@ -122,6 +124,7 @@ abstract class ThreadingDomain {
|
||||
* IllegalStateException} if nothing is currently queued, see {@link #hasQueued()}.
|
||||
* This method must be called from the threading domain's thread.
|
||||
*/
|
||||
@DurationMillisLong
|
||||
long getQueuedDelayMillis() {
|
||||
assertCurrentThread();
|
||||
if (!mIsQueued) {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 com.android.server.location.timezone;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.service.timezone.TimeZoneProviderService;
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An event from a {@link TimeZoneProviderService}.
|
||||
*/
|
||||
final class TimeZoneProviderEvent {
|
||||
|
||||
@IntDef(prefix = "EVENT_TYPE_",
|
||||
value = { EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUGGESTION, EVENT_TYPE_UNCERTAIN })
|
||||
public @interface EventType {}
|
||||
|
||||
/**
|
||||
* The provider failed permanently. See {@link
|
||||
* TimeZoneProviderService#reportPermanentFailure(Throwable)}
|
||||
*/
|
||||
public static final int EVENT_TYPE_PERMANENT_FAILURE = 1;
|
||||
|
||||
/**
|
||||
* The provider made a suggestion. See {@link
|
||||
* TimeZoneProviderService#reportSuggestion(TimeZoneProviderSuggestion)}
|
||||
*/
|
||||
public static final int EVENT_TYPE_SUGGESTION = 2;
|
||||
|
||||
/**
|
||||
* The provider was uncertain about the time zone. See {@link
|
||||
* TimeZoneProviderService#reportUncertain()}
|
||||
*/
|
||||
public static final int EVENT_TYPE_UNCERTAIN = 3;
|
||||
|
||||
private static final TimeZoneProviderEvent UNCERTAIN_EVENT =
|
||||
new TimeZoneProviderEvent(EVENT_TYPE_UNCERTAIN, null, null);
|
||||
|
||||
@EventType
|
||||
private final int mType;
|
||||
|
||||
@Nullable
|
||||
private final TimeZoneProviderSuggestion mSuggestion;
|
||||
|
||||
@Nullable
|
||||
private final String mFailureCause;
|
||||
|
||||
private TimeZoneProviderEvent(@EventType int type,
|
||||
@Nullable TimeZoneProviderSuggestion suggestion,
|
||||
@Nullable String failureCause) {
|
||||
mType = type;
|
||||
mSuggestion = suggestion;
|
||||
mFailureCause = failureCause;
|
||||
}
|
||||
|
||||
/** Returns a event of type {@link #EVENT_TYPE_SUGGESTION}. */
|
||||
public static TimeZoneProviderEvent createSuggestionEvent(
|
||||
@NonNull TimeZoneProviderSuggestion suggestion) {
|
||||
return new TimeZoneProviderEvent(EVENT_TYPE_SUGGESTION,
|
||||
Objects.requireNonNull(suggestion), null);
|
||||
}
|
||||
|
||||
/** Returns a event of type {@link #EVENT_TYPE_UNCERTAIN}. */
|
||||
public static TimeZoneProviderEvent createUncertainEvent() {
|
||||
return UNCERTAIN_EVENT;
|
||||
}
|
||||
|
||||
/** Returns a event of type {@link #EVENT_TYPE_PERMANENT_FAILURE}. */
|
||||
public static TimeZoneProviderEvent createPermanentFailureEvent(@NonNull String cause) {
|
||||
return new TimeZoneProviderEvent(EVENT_TYPE_PERMANENT_FAILURE, null,
|
||||
Objects.requireNonNull(cause));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type.
|
||||
*/
|
||||
public @EventType int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the suggestion. Populated when {@link #getType()} is {@link #EVENT_TYPE_SUGGESTION}.
|
||||
*/
|
||||
@Nullable
|
||||
public TimeZoneProviderSuggestion getSuggestion() {
|
||||
return mSuggestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the failure cauese. Populated when {@link #getType()} is {@link
|
||||
* #EVENT_TYPE_PERMANENT_FAILURE}.
|
||||
*/
|
||||
@Nullable
|
||||
public String getFailureCause() {
|
||||
return mFailureCause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneProviderEvent{"
|
||||
+ "mType=" + mType
|
||||
+ ", mSuggestion=" + mSuggestion
|
||||
+ ", mFailureCause=" + mFailureCause
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TimeZoneProviderEvent that = (TimeZoneProviderEvent) o;
|
||||
return mType == that.mType
|
||||
&& Objects.equals(mSuggestion, that.mSuggestion)
|
||||
&& Objects.equals(mFailureCause, that.mFailureCause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mType, mSuggestion, mFailureCause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 com.android.server.location.timezone;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class encapsulates a request to a provider.
|
||||
*/
|
||||
final class TimeZoneProviderRequest {
|
||||
|
||||
@NonNull
|
||||
private static final TimeZoneProviderRequest STOP_UPDATES =
|
||||
new TimeZoneProviderRequest(
|
||||
false /* sendUpdates */,
|
||||
null /* initializationTimeout */);
|
||||
|
||||
private final boolean mSendUpdates;
|
||||
|
||||
@Nullable
|
||||
private final Duration mInitializationTimeout;
|
||||
|
||||
private TimeZoneProviderRequest(
|
||||
boolean sendUpdates, @Nullable Duration initializationTimeout) {
|
||||
mSendUpdates = sendUpdates;
|
||||
mInitializationTimeout = initializationTimeout;
|
||||
}
|
||||
|
||||
/** Creates a request to start updates with the specified timeout. */
|
||||
public static TimeZoneProviderRequest createStartUpdatesRequest(
|
||||
@NonNull Duration initializationTimeout) {
|
||||
return new TimeZoneProviderRequest(true, Objects.requireNonNull(initializationTimeout));
|
||||
}
|
||||
|
||||
/** Creates a request to stop updates. */
|
||||
public static TimeZoneProviderRequest createStopUpdatesRequest() {
|
||||
return STOP_UPDATES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provider should send updates related to the device's current
|
||||
* time zone, {@code false} otherwise.
|
||||
*/
|
||||
public boolean sendUpdates() {
|
||||
return mSendUpdates;
|
||||
}
|
||||
|
||||
// TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to
|
||||
// be passed to the TimeZoneProviderService and remove if it is not useful.
|
||||
/**
|
||||
* Returns the maximum time that the provider is allowed to initialize before it is expected to
|
||||
* send an event of any sort. Only valid when {@link #sendUpdates()} is {@code true}. Failure to
|
||||
* send an event in this time (with some fuzz) may be interpreted as if the provider is
|
||||
* uncertain of the time zone, and/or it could lead to the provider being stopped.
|
||||
*/
|
||||
@Nullable
|
||||
public Duration getInitializationTimeout() {
|
||||
return mInitializationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TimeZoneProviderRequest
|
||||
that = (TimeZoneProviderRequest) o;
|
||||
return mSendUpdates == that.mSendUpdates
|
||||
&& mInitializationTimeout == that.mInitializationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mSendUpdates, mInitializationTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneProviderRequest{"
|
||||
+ "mSendUpdates=" + mSendUpdates
|
||||
+ ", mInitializationTimeout=" + mInitializationTimeout
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
|
||||
import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
|
||||
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_DISABLED;
|
||||
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
|
||||
import static com.android.server.location.timezone.TestSupport.USER2_CONFIG_GEO_DETECTION_ENABLED;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.createPermanentFailureEvent;
|
||||
import static com.android.server.location.timezone.TimeZoneProviderEvent.createUncertainEvent;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -37,9 +36,9 @@ import static java.util.Arrays.asList;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.location.timezone.LocationTimeZoneEvent;
|
||||
import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
|
||||
import com.android.server.timezonedetector.ConfigurationInternal;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
@@ -61,14 +60,14 @@ public class ControllerImplTest {
|
||||
|
||||
private static final long ARBITRARY_TIME_MILLIS = 12345L;
|
||||
|
||||
private static final LocationTimeZoneEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1 =
|
||||
createLocationTimeZoneEvent(EVENT_TYPE_SUCCESS, asList("Europe/London"));
|
||||
private static final LocationTimeZoneEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2 =
|
||||
createLocationTimeZoneEvent(EVENT_TYPE_SUCCESS, asList("Europe/Paris"));
|
||||
private static final LocationTimeZoneEvent USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT =
|
||||
createLocationTimeZoneEvent(EVENT_TYPE_UNCERTAIN, null);
|
||||
private static final LocationTimeZoneEvent USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT =
|
||||
createLocationTimeZoneEvent(EVENT_TYPE_PERMANENT_FAILURE, null);
|
||||
private static final TimeZoneProviderEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1 =
|
||||
createSuggestionEvent(asList("Europe/London"));
|
||||
private static final TimeZoneProviderEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2 =
|
||||
createSuggestionEvent(asList("Europe/Paris"));
|
||||
private static final TimeZoneProviderEvent USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT =
|
||||
createUncertainEvent();
|
||||
private static final TimeZoneProviderEvent USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT =
|
||||
createPermanentFailureEvent("Test");
|
||||
|
||||
private TestThreadingDomain mTestThreadingDomain;
|
||||
private TestCallback mTestCallback;
|
||||
@@ -89,7 +88,7 @@ public class ControllerImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialState_enabled() {
|
||||
public void initialState_started() {
|
||||
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
|
||||
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
|
||||
TestEnvironment testEnvironment = new TestEnvironment(
|
||||
@@ -98,16 +97,16 @@ public class ControllerImplTest {
|
||||
.plus(testEnvironment.getProviderInitializationTimeoutFuzz());
|
||||
|
||||
// Initialize. After initialization the providers must be initialized and one should be
|
||||
// enabled.
|
||||
// started.
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -120,14 +119,14 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
|
||||
|
||||
// Initialize. After initialization the providers must be initialized but neither should be
|
||||
// enabled.
|
||||
// started.
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -143,8 +142,8 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -152,11 +151,11 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
// The primary should have reported uncertainty, which should trigger the controller to
|
||||
// start the uncertainty timeout and enable the secondary.
|
||||
// start the uncertainty timeout and start the secondary.
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
@@ -167,9 +166,9 @@ public class ControllerImplTest {
|
||||
// Now both initialization timeouts should have triggered. The uncertainty timeout should
|
||||
// still not be triggered.
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
@@ -178,9 +177,9 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -196,21 +195,21 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
// suggestion to be made.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -225,8 +224,8 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -234,22 +233,22 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
// suggestion to be made and the secondary to be shut down.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -264,8 +263,8 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -273,23 +272,23 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
// suggestion to be made.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -304,42 +303,42 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
// suggestion to be made.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// A second, identical event should not cause another suggestion.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// And a third, different event should cause another suggestion.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -354,8 +353,8 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -363,46 +362,46 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
// suggestion to be made.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// A second, identical event should not cause another suggestion.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// And a third, different event should cause another suggestion.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -417,60 +416,60 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
// suggestion to be made and ensure the primary is considered initialized.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event being received from the primary provider. This should not
|
||||
// cause a suggestion to be made straight away, but the uncertainty timeout should be
|
||||
// started and the secondary should be enabled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// started and the secondary should be started.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
// suggestion to be made, cancel the uncertainty timeout and ensure the secondary is
|
||||
// considered initialized.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event being received from the secondary provider. This should not
|
||||
// cause a suggestion to be made straight away, but the uncertainty timeout should be
|
||||
// started. Both providers are now enabled, with no initialization timeout set.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// started. Both providers are now started, with no initialization timeout set.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
@@ -479,9 +478,9 @@ public class ControllerImplTest {
|
||||
mTestThreadingDomain.executeNext();
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -497,46 +496,46 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
// suggestion to be made.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Uncertainty should not cause a suggestion to be made straight away, but the uncertainty
|
||||
// timeout should be started and the secondary should be enabled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// timeout should be started and the secondary should be started.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// And a success event from the primary provider should cause the controller to make another
|
||||
// suggestion, the uncertainty timeout should be cancelled and the secondary should be
|
||||
// disabled again.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// stopped again.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -550,8 +549,8 @@ public class ControllerImplTest {
|
||||
// Initialize and check initial state.
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -559,16 +558,16 @@ public class ControllerImplTest {
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -583,8 +582,8 @@ public class ControllerImplTest {
|
||||
// Initialize and check initial state.
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -592,20 +591,20 @@ public class ControllerImplTest {
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a success event being received from the primary provider.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
@@ -614,8 +613,8 @@ public class ControllerImplTest {
|
||||
// of the time zone.
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -631,35 +630,35 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate the primary provider suggesting a time zone.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
|
||||
// Receiving a "success" provider event should cause a suggestion to be made synchronously,
|
||||
// and also clear the scheduled uncertainty suggestion.
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate the user change (but geo detection still enabled).
|
||||
testEnvironment.simulateConfigChange(USER2_CONFIG_GEO_DETECTION_ENABLED);
|
||||
|
||||
// We expect the provider to end up in PROVIDER_STATE_ENABLED, but it should have been
|
||||
// disabled when the user changed.
|
||||
// We expect the provider to end up in PROVIDER_STATE_STARTED_INITIALIZING, but it should
|
||||
// have been stopped when the user changed.
|
||||
int[] expectedStateTransitions =
|
||||
{ PROVIDER_STATE_DISABLED, PROVIDER_STATE_ENABLED_INITIALIZING };
|
||||
{ PROVIDER_STATE_STOPPED, PROVIDER_STATE_STARTED_INITIALIZING };
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions);
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -674,51 +673,51 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure location event being received from the primary provider. This should
|
||||
// cause the secondary to be enabled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// cause the secondary to be started.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate uncertainty from the secondary.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// And a success event from the secondary provider should cause the controller to make
|
||||
// another suggestion, the uncertainty timeout should be cancelled.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate uncertainty from the secondary.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
}
|
||||
@@ -734,19 +733,19 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure location event being received from the primary provider. This should
|
||||
// cause the secondary to be enabled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// cause the secondary to be started.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -754,7 +753,7 @@ public class ControllerImplTest {
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -763,7 +762,7 @@ public class ControllerImplTest {
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -779,52 +778,52 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event from the primary. This will enable the secondary, which will
|
||||
// Simulate an uncertain event from the primary. This will start the secondary, which will
|
||||
// give this test the opportunity to simulate its failure. Then it will be possible to
|
||||
// demonstrate controller behavior with only the primary working.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate failure event from the secondary. This should just affect the secondary's state.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// And a success event from the primary provider should cause the controller to make
|
||||
// a suggestion, the uncertainty timeout should be cancelled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertSuggestionMadeAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getSuggestion().getTimeZoneIds());
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate uncertainty from the primary. The secondary cannot be enabled.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// Simulate uncertainty from the primary. The secondary cannot be started.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
@@ -841,30 +840,30 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event from the primary. This will enable the secondary, which will
|
||||
// Simulate an uncertain event from the primary. This will start the secondary, which will
|
||||
// give this test the opportunity to simulate its failure. Then it will be possible to
|
||||
// demonstrate controller behavior with only the primary working.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
|
||||
// Simulate failure event from the secondary. This should just affect the secondary's state.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
|
||||
@@ -872,17 +871,17 @@ public class ControllerImplTest {
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is enabled. Only the primary can be
|
||||
// enabled.
|
||||
// started.
|
||||
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
@@ -899,23 +898,23 @@ public class ControllerImplTest {
|
||||
controllerImpl.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure event from the primary. This will enable the secondary.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
// Simulate a failure event from the primary. This will start the secondary.
|
||||
mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate failure event from the secondary.
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
|
||||
mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
|
||||
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
@@ -932,18 +931,14 @@ public class ControllerImplTest {
|
||||
controller.getUncertaintyTimeoutDelayMillis());
|
||||
}
|
||||
|
||||
private static LocationTimeZoneEvent createLocationTimeZoneEvent(
|
||||
int eventType, @Nullable List<String> timeZoneIds) {
|
||||
LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS)
|
||||
.setEventType(eventType);
|
||||
if (timeZoneIds != null) {
|
||||
builder.setTimeZoneIds(timeZoneIds);
|
||||
}
|
||||
return builder.build();
|
||||
private static TimeZoneProviderEvent createSuggestionEvent(@NonNull List<String> timeZoneIds) {
|
||||
return TimeZoneProviderEvent.createSuggestionEvent(
|
||||
new TimeZoneProviderSuggestion.Builder()
|
||||
.setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS)
|
||||
.setTimeZoneIds(timeZoneIds)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private static class TestEnvironment extends LocationTimeZoneProviderController.Environment {
|
||||
|
||||
// These timeouts are set deliberately so that:
|
||||
@@ -1048,12 +1043,12 @@ public class ControllerImplTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
void onEnable(Duration initializationTimeout) {
|
||||
void onStartUpdates(Duration initializationTimeout) {
|
||||
// Nothing needed for tests.
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDisable() {
|
||||
void onStopUpdates() {
|
||||
// Nothing needed for tests.
|
||||
}
|
||||
|
||||
@@ -1078,9 +1073,9 @@ public class ControllerImplTest {
|
||||
mTestProviderState.commitLatest();
|
||||
}
|
||||
|
||||
void assertIsDisabledAndCommit() {
|
||||
// A disabled provider doesn't hold config.
|
||||
assertStateEnumAndConfig(PROVIDER_STATE_DISABLED, null /* config */);
|
||||
void assertIsStoppedAndCommit() {
|
||||
// A stopped provider doesn't hold config.
|
||||
assertStateEnumAndConfig(PROVIDER_STATE_STOPPED, null /* config */);
|
||||
mTestProviderState.commitLatest();
|
||||
}
|
||||
|
||||
@@ -1107,7 +1102,7 @@ public class ControllerImplTest {
|
||||
|
||||
// If and only if the controller is initializing, the initialization timeout must be
|
||||
// set.
|
||||
assertEquals(expectedStateEnum == PROVIDER_STATE_ENABLED_INITIALIZING,
|
||||
assertEquals(expectedStateEnum == PROVIDER_STATE_STARTED_INITIALIZING,
|
||||
isInitializationTimeoutSet());
|
||||
|
||||
assertConfig(expectedConfig);
|
||||
@@ -1123,8 +1118,8 @@ public class ControllerImplTest {
|
||||
assertEquals(expectedTimeout, getInitializationTimeoutDelay());
|
||||
}
|
||||
|
||||
void simulateLocationTimeZoneEvent(@NonNull LocationTimeZoneEvent event) {
|
||||
handleLocationTimeZoneEvent(event);
|
||||
void simulateTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent event) {
|
||||
handleTimeZoneProviderEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
|
||||
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
|
||||
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -61,14 +61,14 @@ public class NullLocationTimeZoneProviderTest {
|
||||
provider.initialize(providerState -> mTestController.onProviderStateChange(providerState));
|
||||
|
||||
ProviderState currentState = provider.getCurrentState();
|
||||
assertEquals(PROVIDER_STATE_DISABLED, currentState.stateEnum);
|
||||
assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
|
||||
assertNull(currentState.currentUserConfiguration);
|
||||
assertSame(provider, currentState.provider);
|
||||
mTestThreadingDomain.assertQueueEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableSchedulesPermFailure() {
|
||||
public void startSchedulesPermFailure() {
|
||||
String providerName = "primary";
|
||||
NullLocationTimeZoneProvider provider =
|
||||
new NullLocationTimeZoneProvider(mTestThreadingDomain, providerName);
|
||||
@@ -77,13 +77,14 @@ public class NullLocationTimeZoneProviderTest {
|
||||
ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
|
||||
Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
|
||||
Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2);
|
||||
provider.enable(config, arbitraryInitializationTimeout, arbitraryInitializationTimeoutFuzz);
|
||||
provider.startUpdates(config, arbitraryInitializationTimeout,
|
||||
arbitraryInitializationTimeoutFuzz);
|
||||
|
||||
// The NullProvider should enter the enabled state, but have schedule an immediate runnable
|
||||
// to switch to perm failure.
|
||||
ProviderState currentState = provider.getCurrentState();
|
||||
assertSame(provider, currentState.provider);
|
||||
assertEquals(PROVIDER_STATE_ENABLED_INITIALIZING, currentState.stateEnum);
|
||||
assertEquals(PROVIDER_STATE_STARTED_INITIALIZING, currentState.stateEnum);
|
||||
assertEquals(config, currentState.currentUserConfiguration);
|
||||
mTestThreadingDomain.assertNextQueueItemIsImmediate();
|
||||
// Entering enabled() does not trigger an onProviderStateChanged() as it is requested by the
|
||||
|
||||
Reference in New Issue
Block a user