Merge "Add status to TimeZoneCapabilitiesAndConfig"
This commit is contained in:
227
core/java/android/app/time/DetectorStatusTypes.java
Normal file
227
core/java/android/app/time/DetectorStatusTypes.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.time;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A set of constants that can relate to time or time zone detector status.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Detector status - the status of the overall detector.</li>
|
||||
* <li>Detection algorithm status - the status of an algorithm that a detector can use.
|
||||
* Each detector is expected to have one or more known algorithms to detect its chosen property,
|
||||
* e.g. for time zone devices can have a "location" detection algorithm, where the device's
|
||||
* location is used to detect the time zone.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class DetectorStatusTypes {
|
||||
|
||||
/** A status code for a detector. */
|
||||
@IntDef(prefix = "DETECTOR_STATUS_", value = {
|
||||
DETECTOR_STATUS_UNKNOWN,
|
||||
DETECTOR_STATUS_NOT_SUPPORTED,
|
||||
DETECTOR_STATUS_NOT_RUNNING,
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
})
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DetectorStatus {}
|
||||
|
||||
/**
|
||||
* The detector status is unknown. Expected only for use as a placeholder before the actual
|
||||
* status is known.
|
||||
*/
|
||||
public static final @DetectorStatus int DETECTOR_STATUS_UNKNOWN = 0;
|
||||
|
||||
/** The detector is not supported on this device. */
|
||||
public static final @DetectorStatus int DETECTOR_STATUS_NOT_SUPPORTED = 1;
|
||||
|
||||
/** The detector is supported but is not running. */
|
||||
public static final @DetectorStatus int DETECTOR_STATUS_NOT_RUNNING = 2;
|
||||
|
||||
/** The detector is supported and is running. */
|
||||
public static final @DetectorStatus int DETECTOR_STATUS_RUNNING = 3;
|
||||
|
||||
private DetectorStatusTypes() {}
|
||||
|
||||
/**
|
||||
* A status code for a detection algorithm.
|
||||
*/
|
||||
@IntDef(prefix = "DETECTION_ALGORITHM_STATUS_", value = {
|
||||
DETECTION_ALGORITHM_STATUS_UNKNOWN,
|
||||
DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED,
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
})
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DetectionAlgorithmStatus {}
|
||||
|
||||
/**
|
||||
* The detection algorithm status is unknown. Expected only for use as a placeholder before the
|
||||
* actual status is known.
|
||||
*/
|
||||
public static final @DetectionAlgorithmStatus int DETECTION_ALGORITHM_STATUS_UNKNOWN = 0;
|
||||
|
||||
/** The detection algorithm is not supported on this device. */
|
||||
public static final @DetectionAlgorithmStatus int DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED = 1;
|
||||
|
||||
/** The detection algorithm supported but is not running. */
|
||||
public static final @DetectionAlgorithmStatus int DETECTION_ALGORITHM_STATUS_NOT_RUNNING = 2;
|
||||
|
||||
/** The detection algorithm supported and is running. */
|
||||
public static final @DetectionAlgorithmStatus int DETECTION_ALGORITHM_STATUS_RUNNING = 3;
|
||||
|
||||
/**
|
||||
* Validates the supplied value is one of the known {@code DETECTOR_STATUS_} constants and
|
||||
* returns it if it is valid. {@link #DETECTOR_STATUS_UNKNOWN} is considered valid.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized
|
||||
*/
|
||||
public static @DetectorStatus int requireValidDetectorStatus(
|
||||
@DetectorStatus int detectorStatus) {
|
||||
if (detectorStatus < DETECTOR_STATUS_UNKNOWN || detectorStatus > DETECTOR_STATUS_RUNNING) {
|
||||
throw new IllegalArgumentException("Invalid detector status: " + detectorStatus);
|
||||
}
|
||||
return detectorStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for each {@code DETECTOR_STATUS_} constant. See also
|
||||
* {@link #detectorStatusFromString(String)}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized
|
||||
*/
|
||||
@NonNull
|
||||
public static String detectorStatusToString(@DetectorStatus int detectorStatus) {
|
||||
switch (detectorStatus) {
|
||||
case DETECTOR_STATUS_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case DETECTOR_STATUS_NOT_SUPPORTED:
|
||||
return "NOT_SUPPORTED";
|
||||
case DETECTOR_STATUS_NOT_RUNNING:
|
||||
return "NOT_RUNNING";
|
||||
case DETECTOR_STATUS_RUNNING:
|
||||
return "RUNNING";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown status: " + detectorStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code DETECTOR_STATUS_} constant value from a string. See also
|
||||
* {@link #detectorStatusToString(int)}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized or is invalid
|
||||
*/
|
||||
public static @DetectorStatus int detectorStatusFromString(
|
||||
@Nullable String detectorStatusString) {
|
||||
if (TextUtils.isEmpty(detectorStatusString)) {
|
||||
throw new IllegalArgumentException("Empty status: " + detectorStatusString);
|
||||
}
|
||||
|
||||
switch (detectorStatusString) {
|
||||
case "UNKNOWN":
|
||||
return DETECTOR_STATUS_UNKNOWN;
|
||||
case "NOT_SUPPORTED":
|
||||
return DETECTOR_STATUS_NOT_SUPPORTED;
|
||||
case "NOT_RUNNING":
|
||||
return DETECTOR_STATUS_NOT_RUNNING;
|
||||
case "RUNNING":
|
||||
return DETECTOR_STATUS_RUNNING;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown status: " + detectorStatusString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the supplied value is one of the known {@code DETECTION_ALGORITHM_} constants and
|
||||
* returns it if it is valid. {@link #DETECTION_ALGORITHM_STATUS_UNKNOWN} is considered valid.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized
|
||||
*/
|
||||
public static @DetectionAlgorithmStatus int requireValidDetectionAlgorithmStatus(
|
||||
@DetectionAlgorithmStatus int detectionAlgorithmStatus) {
|
||||
if (detectionAlgorithmStatus < DETECTION_ALGORITHM_STATUS_UNKNOWN
|
||||
|| detectionAlgorithmStatus > DETECTION_ALGORITHM_STATUS_RUNNING) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid detection algorithm: " + detectionAlgorithmStatus);
|
||||
}
|
||||
return detectionAlgorithmStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for each {@code DETECTION_ALGORITHM_} constant. See also
|
||||
* {@link #detectionAlgorithmStatusFromString(String)}
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized
|
||||
*/
|
||||
@NonNull
|
||||
public static String detectionAlgorithmStatusToString(
|
||||
@DetectionAlgorithmStatus int detectorAlgorithmStatus) {
|
||||
switch (detectorAlgorithmStatus) {
|
||||
case DETECTION_ALGORITHM_STATUS_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED:
|
||||
return "NOT_SUPPORTED";
|
||||
case DETECTION_ALGORITHM_STATUS_NOT_RUNNING:
|
||||
return "NOT_RUNNING";
|
||||
case DETECTION_ALGORITHM_STATUS_RUNNING:
|
||||
return "RUNNING";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown status: " + detectorAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code DETECTION_ALGORITHM_} constant value from a string. See also
|
||||
* {@link #detectionAlgorithmStatusToString(int)} (String)}
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not recognized or is invalid
|
||||
*/
|
||||
public static @DetectionAlgorithmStatus int detectionAlgorithmStatusFromString(
|
||||
@Nullable String detectorAlgorithmStatusString) {
|
||||
|
||||
if (TextUtils.isEmpty(detectorAlgorithmStatusString)) {
|
||||
throw new IllegalArgumentException("Empty status: " + detectorAlgorithmStatusString);
|
||||
}
|
||||
|
||||
switch (detectorAlgorithmStatusString) {
|
||||
case "UNKNOWN":
|
||||
return DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
case "NOT_SUPPORTED":
|
||||
return DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
|
||||
case "NOT_RUNNING":
|
||||
return DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
case "RUNNING":
|
||||
return DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown status: " + detectorAlgorithmStatusString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
parcelable LocationTimeZoneAlgorithmStatus;
|
||||
363
core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java
Normal file
363
core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
import static android.app.time.DetectorStatusTypes.detectionAlgorithmStatusFromString;
|
||||
import static android.app.time.DetectorStatusTypes.detectionAlgorithmStatusToString;
|
||||
import static android.app.time.DetectorStatusTypes.requireValidDetectionAlgorithmStatus;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.service.timezone.TimeZoneProviderStatus;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Information about the status of the location-based time zone detection algorithm.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class LocationTimeZoneAlgorithmStatus implements Parcelable {
|
||||
|
||||
/**
|
||||
* An enum that describes a location time zone provider's status.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "PROVIDER_STATUS_", value = {
|
||||
PROVIDER_STATUS_NOT_PRESENT,
|
||||
PROVIDER_STATUS_NOT_READY,
|
||||
PROVIDER_STATUS_IS_CERTAIN,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN,
|
||||
})
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ProviderStatus {}
|
||||
|
||||
/**
|
||||
* Indicates a provider is not present because it has not been configured, the configuration
|
||||
* is bad, or the provider has reported a permanent failure.
|
||||
*/
|
||||
public static final @ProviderStatus int PROVIDER_STATUS_NOT_PRESENT = 1;
|
||||
|
||||
/**
|
||||
* Indicates a provider has not reported it is certain or uncertain. This may be because it has
|
||||
* just started running, or it has been stopped.
|
||||
*/
|
||||
public static final @ProviderStatus int PROVIDER_STATUS_NOT_READY = 2;
|
||||
|
||||
/**
|
||||
* Indicates a provider last reported it is certain.
|
||||
*/
|
||||
public static final @ProviderStatus int PROVIDER_STATUS_IS_CERTAIN = 3;
|
||||
|
||||
/**
|
||||
* Indicates a provider last reported it is uncertain.
|
||||
*/
|
||||
public static final @ProviderStatus int PROVIDER_STATUS_IS_UNCERTAIN = 4;
|
||||
|
||||
/**
|
||||
* An instance that provides no information about algorithm status because the algorithm has not
|
||||
* yet reported. Effectively a "null" status placeholder.
|
||||
*/
|
||||
@NonNull
|
||||
public static final LocationTimeZoneAlgorithmStatus UNKNOWN =
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_UNKNOWN,
|
||||
PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
|
||||
|
||||
private final @DetectionAlgorithmStatus int mStatus;
|
||||
private final @ProviderStatus int mPrimaryProviderStatus;
|
||||
// May be populated when mPrimaryProviderReportedStatus == PROVIDER_STATUS_IS_CERTAIN
|
||||
// or PROVIDER_STATUS_IS_UNCERTAIN
|
||||
@Nullable private final TimeZoneProviderStatus mPrimaryProviderReportedStatus;
|
||||
|
||||
private final @ProviderStatus int mSecondaryProviderStatus;
|
||||
// May be populated when mSecondaryProviderReportedStatus == PROVIDER_STATUS_IS_CERTAIN
|
||||
// or PROVIDER_STATUS_IS_UNCERTAIN
|
||||
@Nullable private final TimeZoneProviderStatus mSecondaryProviderReportedStatus;
|
||||
|
||||
public LocationTimeZoneAlgorithmStatus(
|
||||
@DetectionAlgorithmStatus int status,
|
||||
@ProviderStatus int primaryProviderStatus,
|
||||
@Nullable TimeZoneProviderStatus primaryProviderReportedStatus,
|
||||
@ProviderStatus int secondaryProviderStatus,
|
||||
@Nullable TimeZoneProviderStatus secondaryProviderReportedStatus) {
|
||||
|
||||
mStatus = requireValidDetectionAlgorithmStatus(status);
|
||||
mPrimaryProviderStatus = requireValidProviderStatus(primaryProviderStatus);
|
||||
mPrimaryProviderReportedStatus = primaryProviderReportedStatus;
|
||||
mSecondaryProviderStatus = requireValidProviderStatus(secondaryProviderStatus);
|
||||
mSecondaryProviderReportedStatus = secondaryProviderReportedStatus;
|
||||
|
||||
boolean primaryProviderHasReported = hasProviderReported(primaryProviderStatus);
|
||||
boolean primaryProviderReportedStatusPresent = primaryProviderReportedStatus != null;
|
||||
if (!primaryProviderHasReported && primaryProviderReportedStatusPresent) {
|
||||
throw new IllegalArgumentException(
|
||||
"primaryProviderReportedStatus=" + primaryProviderReportedStatus
|
||||
+ ", primaryProviderStatus="
|
||||
+ providerStatusToString(primaryProviderStatus));
|
||||
}
|
||||
|
||||
boolean secondaryProviderHasReported = hasProviderReported(secondaryProviderStatus);
|
||||
boolean secondaryProviderReportedStatusPresent = secondaryProviderReportedStatus != null;
|
||||
if (!secondaryProviderHasReported && secondaryProviderReportedStatusPresent) {
|
||||
throw new IllegalArgumentException(
|
||||
"secondaryProviderReportedStatus=" + secondaryProviderReportedStatus
|
||||
+ ", secondaryProviderStatus="
|
||||
+ providerStatusToString(secondaryProviderStatus));
|
||||
}
|
||||
|
||||
// If the algorithm isn't running, providers can't report.
|
||||
if (status != DETECTION_ALGORITHM_STATUS_RUNNING
|
||||
&& (primaryProviderHasReported || secondaryProviderHasReported)) {
|
||||
throw new IllegalArgumentException(
|
||||
"algorithmStatus=" + detectionAlgorithmStatusToString(status)
|
||||
+ ", primaryProviderReportedStatus=" + primaryProviderReportedStatus
|
||||
+ ", secondaryProviderReportedStatus="
|
||||
+ secondaryProviderReportedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status value of the detection algorithm.
|
||||
*/
|
||||
public @DetectionAlgorithmStatus int getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the primary location time zone provider as categorized by the detection
|
||||
* algorithm.
|
||||
*/
|
||||
public @ProviderStatus int getPrimaryProviderStatus() {
|
||||
return mPrimaryProviderStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the primary location time zone provider as reported by the provider
|
||||
* itself. Can be {@code null} when the provider hasn't reported, or omitted when it has.
|
||||
*/
|
||||
@Nullable
|
||||
public TimeZoneProviderStatus getPrimaryProviderReportedStatus() {
|
||||
return mPrimaryProviderReportedStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the secondary location time zone provider as categorized by the
|
||||
* detection algorithm.
|
||||
*/
|
||||
public @ProviderStatus int getSecondaryProviderStatus() {
|
||||
return mSecondaryProviderStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the secondary location time zone provider as reported by the provider
|
||||
* itself. Can be {@code null} when the provider hasn't reported, or omitted when it has.
|
||||
*/
|
||||
@Nullable
|
||||
public TimeZoneProviderStatus getSecondaryProviderReportedStatus() {
|
||||
return mSecondaryProviderReportedStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocationTimeZoneAlgorithmStatus{"
|
||||
+ "mAlgorithmStatus=" + detectionAlgorithmStatusToString(mStatus)
|
||||
+ ", mPrimaryProviderStatus=" + providerStatusToString(mPrimaryProviderStatus)
|
||||
+ ", mPrimaryProviderReportedStatus=" + mPrimaryProviderReportedStatus
|
||||
+ ", mSecondaryProviderStatus=" + providerStatusToString(mSecondaryProviderStatus)
|
||||
+ ", mSecondaryProviderReportedStatus=" + mSecondaryProviderReportedStatus
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a {@link LocationTimeZoneAlgorithmStatus} from a toString() string for manual
|
||||
* command-line testing.
|
||||
*/
|
||||
@NonNull
|
||||
public static LocationTimeZoneAlgorithmStatus parseCommandlineArg(@NonNull String arg) {
|
||||
// Note: "}" has to be escaped on Android with "\\}" because the regexp library is not based
|
||||
// on OpenJDK code.
|
||||
Pattern pattern = Pattern.compile("LocationTimeZoneAlgorithmStatus\\{"
|
||||
+ "mAlgorithmStatus=(.+)"
|
||||
+ ", mPrimaryProviderStatus=([^,]+)"
|
||||
+ ", mPrimaryProviderReportedStatus=(null|TimeZoneProviderStatus\\{[^}]+\\})"
|
||||
+ ", mSecondaryProviderStatus=([^,]+)"
|
||||
+ ", mSecondaryProviderReportedStatus=(null|TimeZoneProviderStatus\\{[^}]+\\})"
|
||||
+ "\\}"
|
||||
);
|
||||
Matcher matcher = pattern.matcher(arg);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("Unable to parse algorithm status arg: " + arg);
|
||||
}
|
||||
@DetectionAlgorithmStatus int algorithmStatus =
|
||||
detectionAlgorithmStatusFromString(matcher.group(1));
|
||||
@ProviderStatus int primaryProviderStatus = providerStatusFromString(matcher.group(2));
|
||||
TimeZoneProviderStatus primaryProviderReportedStatus =
|
||||
parseTimeZoneProviderStatusOrNull(matcher.group(3));
|
||||
@ProviderStatus int secondaryProviderStatus = providerStatusFromString(matcher.group(4));
|
||||
TimeZoneProviderStatus secondaryProviderReportedStatus =
|
||||
parseTimeZoneProviderStatusOrNull(matcher.group(5));
|
||||
return new LocationTimeZoneAlgorithmStatus(
|
||||
algorithmStatus, primaryProviderStatus, primaryProviderReportedStatus,
|
||||
secondaryProviderStatus, secondaryProviderReportedStatus);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TimeZoneProviderStatus parseTimeZoneProviderStatusOrNull(
|
||||
String providerReportedStatusString) {
|
||||
TimeZoneProviderStatus providerReportedStatus;
|
||||
if ("null".equals(providerReportedStatusString)) {
|
||||
providerReportedStatus = null;
|
||||
} else {
|
||||
providerReportedStatus =
|
||||
TimeZoneProviderStatus.parseProviderStatus(providerReportedStatusString);
|
||||
}
|
||||
return providerReportedStatus;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<LocationTimeZoneAlgorithmStatus> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public LocationTimeZoneAlgorithmStatus createFromParcel(Parcel in) {
|
||||
@DetectionAlgorithmStatus int algorithmStatus = in.readInt();
|
||||
@ProviderStatus int primaryProviderStatus = in.readInt();
|
||||
TimeZoneProviderStatus primaryProviderReportedStatus =
|
||||
in.readParcelable(getClass().getClassLoader(), TimeZoneProviderStatus.class);
|
||||
@ProviderStatus int secondaryProviderStatus = in.readInt();
|
||||
TimeZoneProviderStatus secondaryProviderReportedStatus =
|
||||
in.readParcelable(getClass().getClassLoader(), TimeZoneProviderStatus.class);
|
||||
return new LocationTimeZoneAlgorithmStatus(
|
||||
algorithmStatus, primaryProviderStatus, primaryProviderReportedStatus,
|
||||
secondaryProviderStatus, secondaryProviderReportedStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationTimeZoneAlgorithmStatus[] newArray(int size) {
|
||||
return new LocationTimeZoneAlgorithmStatus[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||
parcel.writeInt(mStatus);
|
||||
parcel.writeInt(mPrimaryProviderStatus);
|
||||
parcel.writeParcelable(mPrimaryProviderReportedStatus, flags);
|
||||
parcel.writeInt(mSecondaryProviderStatus);
|
||||
parcel.writeParcelable(mSecondaryProviderReportedStatus, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LocationTimeZoneAlgorithmStatus that = (LocationTimeZoneAlgorithmStatus) o;
|
||||
return mStatus == that.mStatus
|
||||
&& mPrimaryProviderStatus == that.mPrimaryProviderStatus
|
||||
&& Objects.equals(
|
||||
mPrimaryProviderReportedStatus, that.mPrimaryProviderReportedStatus)
|
||||
&& mSecondaryProviderStatus == that.mSecondaryProviderStatus
|
||||
&& Objects.equals(
|
||||
mSecondaryProviderReportedStatus, that.mSecondaryProviderReportedStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mStatus,
|
||||
mPrimaryProviderStatus, mPrimaryProviderReportedStatus,
|
||||
mSecondaryProviderStatus, mSecondaryProviderReportedStatus);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
@NonNull
|
||||
public static String providerStatusToString(@ProviderStatus int providerStatus) {
|
||||
switch (providerStatus) {
|
||||
case PROVIDER_STATUS_NOT_PRESENT:
|
||||
return "NOT_PRESENT";
|
||||
case PROVIDER_STATUS_NOT_READY:
|
||||
return "NOT_READY";
|
||||
case PROVIDER_STATUS_IS_CERTAIN:
|
||||
return "IS_CERTAIN";
|
||||
case PROVIDER_STATUS_IS_UNCERTAIN:
|
||||
return "IS_UNCERTAIN";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown status: " + providerStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting public static @ProviderStatus int providerStatusFromString(
|
||||
@Nullable String providerStatusString) {
|
||||
if (TextUtils.isEmpty(providerStatusString)) {
|
||||
throw new IllegalArgumentException("Empty status: " + providerStatusString);
|
||||
}
|
||||
|
||||
switch (providerStatusString) {
|
||||
case "NOT_PRESENT":
|
||||
return PROVIDER_STATUS_NOT_PRESENT;
|
||||
case "NOT_READY":
|
||||
return PROVIDER_STATUS_NOT_READY;
|
||||
case "IS_CERTAIN":
|
||||
return PROVIDER_STATUS_IS_CERTAIN;
|
||||
case "IS_UNCERTAIN":
|
||||
return PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown status: " + providerStatusString);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasProviderReported(@ProviderStatus int providerStatus) {
|
||||
return providerStatus == PROVIDER_STATUS_IS_CERTAIN
|
||||
|| providerStatus == PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting public static @ProviderStatus int requireValidProviderStatus(
|
||||
@ProviderStatus int providerStatus) {
|
||||
if (providerStatus < PROVIDER_STATUS_NOT_PRESENT
|
||||
|| providerStatus > PROVIDER_STATUS_IS_UNCERTAIN) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid provider status: " + providerStatus);
|
||||
}
|
||||
return providerStatus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
parcelable TelephonyTimeZoneAlgorithmStatus;
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.detectionAlgorithmStatusToString;
|
||||
import static android.app.time.DetectorStatusTypes.requireValidDetectionAlgorithmStatus;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Information about the status of the telephony-based time zone detection algorithm.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class TelephonyTimeZoneAlgorithmStatus implements Parcelable {
|
||||
|
||||
private final @DetectionAlgorithmStatus int mAlgorithmStatus;
|
||||
|
||||
public TelephonyTimeZoneAlgorithmStatus(@DetectionAlgorithmStatus int algorithmStatus) {
|
||||
mAlgorithmStatus = requireValidDetectionAlgorithmStatus(algorithmStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the detection algorithm.
|
||||
*/
|
||||
public @DetectionAlgorithmStatus int getAlgorithmStatus() {
|
||||
return mAlgorithmStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TelephonyTimeZoneAlgorithmStatus{"
|
||||
+ "mAlgorithmStatus=" + detectionAlgorithmStatusToString(mAlgorithmStatus)
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<TelephonyTimeZoneAlgorithmStatus> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public TelephonyTimeZoneAlgorithmStatus createFromParcel(Parcel in) {
|
||||
@DetectionAlgorithmStatus int algorithmStatus = in.readInt();
|
||||
return new TelephonyTimeZoneAlgorithmStatus(algorithmStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TelephonyTimeZoneAlgorithmStatus[] newArray(int size) {
|
||||
return new TelephonyTimeZoneAlgorithmStatus[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||
parcel.writeInt(mAlgorithmStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TelephonyTimeZoneAlgorithmStatus that = (TelephonyTimeZoneAlgorithmStatus) o;
|
||||
return mAlgorithmStatus == that.mAlgorithmStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
@@ -23,27 +23,40 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* A pair containing a user's {@link TimeZoneCapabilities} and {@link TimeZoneConfiguration}.
|
||||
* An object containing a user's {@link TimeZoneCapabilities} and {@link TimeZoneConfiguration}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
|
||||
|
||||
public static final @NonNull Creator<TimeZoneCapabilitiesAndConfig> CREATOR =
|
||||
new Creator<TimeZoneCapabilitiesAndConfig>() {
|
||||
public TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
|
||||
return TimeZoneCapabilitiesAndConfig.createFromParcel(in);
|
||||
}
|
||||
|
||||
public TimeZoneCapabilitiesAndConfig[] newArray(int size) {
|
||||
return new TimeZoneCapabilitiesAndConfig[size];
|
||||
}
|
||||
};
|
||||
public static final @NonNull Creator<TimeZoneCapabilitiesAndConfig> CREATOR = new Creator<>() {
|
||||
public TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
|
||||
return TimeZoneCapabilitiesAndConfig.createFromParcel(in);
|
||||
}
|
||||
|
||||
public TimeZoneCapabilitiesAndConfig[] newArray(int size) {
|
||||
return new TimeZoneCapabilitiesAndConfig[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The time zone detector status.
|
||||
*
|
||||
* Implementation note for future platform engineers: This field is only needed by SettingsUI
|
||||
* initially and so it has not been added to the SDK API. {@link TimeZoneDetectorStatus}
|
||||
* contains details about the internals of the time zone detector so thought should be given to
|
||||
* abstraction / exposing a lightweight version if something unbundled needs access to detector
|
||||
* details. Also, that could be good time to add separate APIs for bundled components, or add
|
||||
* new APIs that return something more extensible and generic like a Bundle or a less
|
||||
* constraining name. See also {@link
|
||||
* TimeManager#addTimeZoneDetectorListener(Executor, TimeManager.TimeZoneDetectorListener)},
|
||||
* which notified of changes to any fields in this class, including the detector status.
|
||||
*/
|
||||
@NonNull private final TimeZoneDetectorStatus mDetectorStatus;
|
||||
@NonNull private final TimeZoneCapabilities mCapabilities;
|
||||
@NonNull private final TimeZoneConfiguration mConfiguration;
|
||||
|
||||
@@ -53,25 +66,40 @@ public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public TimeZoneCapabilitiesAndConfig(
|
||||
@NonNull TimeZoneDetectorStatus detectorStatus,
|
||||
@NonNull TimeZoneCapabilities capabilities,
|
||||
@NonNull TimeZoneConfiguration configuration) {
|
||||
this.mCapabilities = Objects.requireNonNull(capabilities);
|
||||
this.mConfiguration = Objects.requireNonNull(configuration);
|
||||
mDetectorStatus = Objects.requireNonNull(detectorStatus);
|
||||
mCapabilities = Objects.requireNonNull(capabilities);
|
||||
mConfiguration = Objects.requireNonNull(configuration);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
|
||||
TimeZoneCapabilities capabilities = in.readParcelable(null, android.app.time.TimeZoneCapabilities.class);
|
||||
TimeZoneConfiguration configuration = in.readParcelable(null, android.app.time.TimeZoneConfiguration.class);
|
||||
return new TimeZoneCapabilitiesAndConfig(capabilities, configuration);
|
||||
TimeZoneDetectorStatus detectorStatus =
|
||||
in.readParcelable(null, TimeZoneDetectorStatus.class);
|
||||
TimeZoneCapabilities capabilities = in.readParcelable(null, TimeZoneCapabilities.class);
|
||||
TimeZoneConfiguration configuration = in.readParcelable(null, TimeZoneConfiguration.class);
|
||||
return new TimeZoneCapabilitiesAndConfig(detectorStatus, capabilities, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mDetectorStatus, flags);
|
||||
dest.writeParcelable(mCapabilities, flags);
|
||||
dest.writeParcelable(mConfiguration, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time zone detector's status.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public TimeZoneDetectorStatus getDetectorStatus() {
|
||||
return mDetectorStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's time zone behavior capabilities.
|
||||
*/
|
||||
@@ -102,7 +130,8 @@ public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
TimeZoneCapabilitiesAndConfig that = (TimeZoneCapabilitiesAndConfig) o;
|
||||
return mCapabilities.equals(that.mCapabilities)
|
||||
return mDetectorStatus.equals(that.mDetectorStatus)
|
||||
&& mCapabilities.equals(that.mCapabilities)
|
||||
&& mConfiguration.equals(that.mConfiguration);
|
||||
}
|
||||
|
||||
@@ -114,7 +143,8 @@ public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneCapabilitiesAndConfig{"
|
||||
+ "mCapabilities=" + mCapabilities
|
||||
+ "mDetectorStatus=" + mDetectorStatus
|
||||
+ ", mCapabilities=" + mCapabilities
|
||||
+ ", mConfiguration=" + mConfiguration
|
||||
+ '}';
|
||||
}
|
||||
|
||||
19
core/java/android/app/time/TimeZoneDetectorStatus.aidl
Normal file
19
core/java/android/app/time/TimeZoneDetectorStatus.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
parcelable TimeZoneDetectorStatus;
|
||||
124
core/java/android/app/time/TimeZoneDetectorStatus.java
Normal file
124
core/java/android/app/time/TimeZoneDetectorStatus.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DetectorStatus;
|
||||
import static android.app.time.DetectorStatusTypes.requireValidDetectorStatus;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Information about the status of the automatic time zone detector. Used by SettingsUI to display
|
||||
* status information to the user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class TimeZoneDetectorStatus implements Parcelable {
|
||||
|
||||
private final @DetectorStatus int mDetectorStatus;
|
||||
@NonNull private final TelephonyTimeZoneAlgorithmStatus mTelephonyTimeZoneAlgorithmStatus;
|
||||
@NonNull private final LocationTimeZoneAlgorithmStatus mLocationTimeZoneAlgorithmStatus;
|
||||
|
||||
public TimeZoneDetectorStatus(
|
||||
@DetectorStatus int detectorStatus,
|
||||
@NonNull TelephonyTimeZoneAlgorithmStatus telephonyTimeZoneAlgorithmStatus,
|
||||
@NonNull LocationTimeZoneAlgorithmStatus locationTimeZoneAlgorithmStatus) {
|
||||
mDetectorStatus = requireValidDetectorStatus(detectorStatus);
|
||||
mTelephonyTimeZoneAlgorithmStatus =
|
||||
Objects.requireNonNull(telephonyTimeZoneAlgorithmStatus);
|
||||
mLocationTimeZoneAlgorithmStatus = Objects.requireNonNull(locationTimeZoneAlgorithmStatus);
|
||||
}
|
||||
|
||||
public @DetectorStatus int getDetectorStatus() {
|
||||
return mDetectorStatus;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public TelephonyTimeZoneAlgorithmStatus getTelephonyTimeZoneAlgorithmStatus() {
|
||||
return mTelephonyTimeZoneAlgorithmStatus;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public LocationTimeZoneAlgorithmStatus getLocationTimeZoneAlgorithmStatus() {
|
||||
return mLocationTimeZoneAlgorithmStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeZoneDetectorStatus{"
|
||||
+ "mDetectorStatus=" + DetectorStatusTypes.detectorStatusToString(mDetectorStatus)
|
||||
+ ", mTelephonyTimeZoneAlgorithmStatus=" + mTelephonyTimeZoneAlgorithmStatus
|
||||
+ ", mLocationTimeZoneAlgorithmStatus=" + mLocationTimeZoneAlgorithmStatus
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<TimeZoneDetectorStatus> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public TimeZoneDetectorStatus createFromParcel(Parcel in) {
|
||||
@DetectorStatus int detectorStatus = in.readInt();
|
||||
TelephonyTimeZoneAlgorithmStatus telephonyTimeZoneAlgorithmStatus =
|
||||
in.readParcelable(getClass().getClassLoader(),
|
||||
TelephonyTimeZoneAlgorithmStatus.class);
|
||||
LocationTimeZoneAlgorithmStatus locationTimeZoneAlgorithmStatus =
|
||||
in.readParcelable(getClass().getClassLoader(),
|
||||
LocationTimeZoneAlgorithmStatus.class);
|
||||
return new TimeZoneDetectorStatus(detectorStatus,
|
||||
telephonyTimeZoneAlgorithmStatus, locationTimeZoneAlgorithmStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneDetectorStatus[] newArray(int size) {
|
||||
return new TimeZoneDetectorStatus[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||
parcel.writeInt(mDetectorStatus);
|
||||
parcel.writeParcelable(mTelephonyTimeZoneAlgorithmStatus, flags);
|
||||
parcel.writeParcelable(mLocationTimeZoneAlgorithmStatus, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TimeZoneDetectorStatus that = (TimeZoneDetectorStatus) o;
|
||||
return mDetectorStatus == that.mDetectorStatus
|
||||
&& mTelephonyTimeZoneAlgorithmStatus.equals(that.mTelephonyTimeZoneAlgorithmStatus)
|
||||
&& mLocationTimeZoneAlgorithmStatus.equals(that.mLocationTimeZoneAlgorithmStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mDetectorStatus, mTelephonyTimeZoneAlgorithmStatus,
|
||||
mLocationTimeZoneAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
@@ -81,11 +81,11 @@ public interface TimeZoneDetector {
|
||||
String SHELL_COMMAND_SET_GEO_DETECTION_ENABLED = "set_geo_detection_enabled";
|
||||
|
||||
/**
|
||||
* A shell command that injects a geolocation time zone suggestion (as if from the
|
||||
* A shell command that injects a location algorithm event (as if from the
|
||||
* location_time_zone_manager).
|
||||
* @hide
|
||||
*/
|
||||
String SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE = "suggest_geo_location_time_zone";
|
||||
String SHELL_COMMAND_HANDLE_LOCATION_ALGORITHM_EVENT = "handle_location_algorithm_event";
|
||||
|
||||
/**
|
||||
* A shell command that injects a manual time zone suggestion (as if from the SettingsUI or
|
||||
|
||||
@@ -40,7 +40,7 @@ enum ControllerStateEnum {
|
||||
message LocationTimeZoneManagerServiceStateProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
optional GeolocationTimeZoneSuggestionProto last_suggestion = 1;
|
||||
optional LocationTimeZoneProviderEventProto last_event = 1;
|
||||
repeated TimeZoneProviderStateProto primary_provider_states = 2;
|
||||
repeated TimeZoneProviderStateProto secondary_provider_states = 3;
|
||||
repeated ControllerStateEnum controller_states = 4;
|
||||
|
||||
@@ -22,13 +22,38 @@ import "frameworks/base/core/proto/android/privacy.proto";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "TimeZoneDetectorProto";
|
||||
|
||||
// Represents a GeolocationTimeZoneSuggestion that can be / has been passed to the time zone
|
||||
// Represents a LocationTimeZoneProviderEvent that can be / has been passed to the time zone
|
||||
// detector.
|
||||
message LocationTimeZoneProviderEventProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
optional GeolocationTimeZoneSuggestionProto suggestion = 1;
|
||||
repeated string debug_info = 2;
|
||||
optional LocationTimeZoneAlgorithmStatusProto algorithm_status = 3;
|
||||
}
|
||||
|
||||
// Represents a LocationTimeZoneAlgorithmStatus that can be / has been passed to the time zone
|
||||
// detector.
|
||||
message LocationTimeZoneAlgorithmStatusProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
optional DetectionAlgorithmStatusEnum status = 1;
|
||||
}
|
||||
|
||||
// The state enum for detection algorithms.
|
||||
enum DetectionAlgorithmStatusEnum {
|
||||
DETECTION_ALGORITHM_STATUS_UNKNOWN = 0;
|
||||
DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED = 1;
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING = 2;
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING = 3;
|
||||
}
|
||||
|
||||
// Represents a GeolocationTimeZoneSuggestion that can be contained in a
|
||||
// LocationTimeZoneProviderEvent.
|
||||
message GeolocationTimeZoneSuggestionProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
repeated string zone_ids = 1;
|
||||
repeated string debug_info = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_UNKNOWN;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.app.time.DetectorStatusTypes.DetectorStatus;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DetectorStatusTypesTest {
|
||||
|
||||
@Test
|
||||
public void testRequireValidDetectionAlgorithmStatus() {
|
||||
for (@DetectionAlgorithmStatus int status = DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
status <= DETECTION_ALGORITHM_STATUS_RUNNING; status++) {
|
||||
assertEquals(status, DetectorStatusTypes.requireValidDetectionAlgorithmStatus(status));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.requireValidDetectionAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_UNKNOWN - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.requireValidDetectionAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatAndParseDetectionAlgorithmStatus() {
|
||||
for (@DetectionAlgorithmStatus int status = DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
status <= DETECTION_ALGORITHM_STATUS_RUNNING; status++) {
|
||||
assertEquals(status, DetectorStatusTypes.detectionAlgorithmStatusFromString(
|
||||
DetectorStatusTypes.detectionAlgorithmStatusToString(status)));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusToString(
|
||||
DETECTION_ALGORITHM_STATUS_UNKNOWN - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusToString(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING + 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString(null));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString(""));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString("FOO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidDetectorStatus() {
|
||||
for (@DetectorStatus int status = DETECTOR_STATUS_UNKNOWN;
|
||||
status <= DETECTOR_STATUS_RUNNING; status++) {
|
||||
assertEquals(status, DetectorStatusTypes.requireValidDetectorStatus(status));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.requireValidDetectorStatus(DETECTOR_STATUS_UNKNOWN - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.requireValidDetectorStatus(DETECTOR_STATUS_RUNNING + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatAndParseDetectorStatus() {
|
||||
for (@DetectorStatus int status = DETECTOR_STATUS_UNKNOWN;
|
||||
status <= DETECTOR_STATUS_RUNNING; status++) {
|
||||
assertEquals(status, DetectorStatusTypes.detectorStatusFromString(
|
||||
DetectorStatusTypes.detectorStatusToString(status)));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusToString(DETECTOR_STATUS_UNKNOWN - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusToString(DETECTOR_STATUS_RUNNING + 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString(null));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString(""));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> DetectorStatusTypes.detectorStatusFromString("FOO"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
|
||||
import static android.app.time.ParcelableTestSupport.assertEqualsAndHashCode;
|
||||
import static android.app.time.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus.ProviderStatus;
|
||||
import android.service.timezone.TimeZoneProviderStatus;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class LocationTimeZoneAlgorithmStatusTest {
|
||||
|
||||
private static final TimeZoneProviderStatus ARBITRARY_PROVIDER_RUNNING_STATUS =
|
||||
new TimeZoneProviderStatus.Builder()
|
||||
.setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
|
||||
.setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
|
||||
.setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void testConstructorValidation() {
|
||||
// Sample some invalid cases
|
||||
|
||||
// There can't be a reported provider status if the algorithm isn't running.
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS));
|
||||
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null));
|
||||
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS));
|
||||
|
||||
// No reported provider status expected if the associated provider isn't ready / present.
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null));
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_READY, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_READY, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, ARBITRARY_PROVIDER_RUNNING_STATUS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
LocationTimeZoneAlgorithmStatus one = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertEqualsAndHashCode(one, one);
|
||||
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus two = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertEqualsAndHashCode(one, two);
|
||||
}
|
||||
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus three = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
PROVIDER_STATUS_NOT_READY, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertNotEquals(one, three);
|
||||
assertNotEquals(three, one);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
// Primary provider only.
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
|
||||
// Secondary provider only
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
|
||||
// Algorithm not running.
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidProviderStatus() {
|
||||
for (@ProviderStatus int status = PROVIDER_STATUS_NOT_PRESENT;
|
||||
status <= PROVIDER_STATUS_IS_UNCERTAIN; status++) {
|
||||
assertEquals(status,
|
||||
LocationTimeZoneAlgorithmStatus.requireValidProviderStatus(status));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.requireValidProviderStatus(
|
||||
PROVIDER_STATUS_NOT_PRESENT - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.requireValidProviderStatus(
|
||||
PROVIDER_STATUS_IS_UNCERTAIN + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatAndParseProviderStatus() {
|
||||
for (@ProviderStatus int status = PROVIDER_STATUS_NOT_PRESENT;
|
||||
status <= PROVIDER_STATUS_IS_UNCERTAIN; status++) {
|
||||
assertEquals(status, LocationTimeZoneAlgorithmStatus.providerStatusFromString(
|
||||
LocationTimeZoneAlgorithmStatus.providerStatusToString(status)));
|
||||
}
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.providerStatusToString(
|
||||
PROVIDER_STATUS_NOT_PRESENT - 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.providerStatusToString(
|
||||
PROVIDER_STATUS_IS_UNCERTAIN + 1));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.providerStatusFromString(null));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.providerStatusFromString(""));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> LocationTimeZoneAlgorithmStatus.providerStatusFromString("FOO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandlineArg_noNullReportedStatuses() {
|
||||
LocationTimeZoneAlgorithmStatus status = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, ARBITRARY_PROVIDER_RUNNING_STATUS);
|
||||
assertEquals(status,
|
||||
LocationTimeZoneAlgorithmStatus.parseCommandlineArg(status.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandlineArg_withNullReportedStatuses() {
|
||||
LocationTimeZoneAlgorithmStatus status = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, null,
|
||||
PROVIDER_STATUS_IS_UNCERTAIN, null);
|
||||
assertEquals(status,
|
||||
LocationTimeZoneAlgorithmStatus.parseCommandlineArg(status.toString()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.ParcelableTestSupport.assertEqualsAndHashCode;
|
||||
import static android.app.time.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TelephonyTimeZoneAlgorithmStatusTest {
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TelephonyTimeZoneAlgorithmStatus one = new TelephonyTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertEqualsAndHashCode(one, one);
|
||||
|
||||
{
|
||||
TelephonyTimeZoneAlgorithmStatus two = new TelephonyTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertEqualsAndHashCode(one, two);
|
||||
}
|
||||
|
||||
{
|
||||
TelephonyTimeZoneAlgorithmStatus three = new TelephonyTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertNotEquals(one, three);
|
||||
assertNotEquals(three, one);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
// Algorithm running.
|
||||
{
|
||||
TelephonyTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new TelephonyTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
|
||||
// Algorithm not running.
|
||||
{
|
||||
TelephonyTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new TelephonyTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.time;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
import static android.app.time.ParcelableTestSupport.assertEqualsAndHashCode;
|
||||
import static android.app.time.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TimeZoneDetectorStatusTest {
|
||||
|
||||
private static final TelephonyTimeZoneAlgorithmStatus ARBITRARY_TELEPHONY_ALGORITHM_STATUS =
|
||||
new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
|
||||
private static final LocationTimeZoneAlgorithmStatus ARBITRARY_LOCATION_ALGORITHM_STATUS =
|
||||
new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY, null,
|
||||
LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
TimeZoneDetectorStatus one = new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING,
|
||||
ARBITRARY_TELEPHONY_ALGORITHM_STATUS, ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertEqualsAndHashCode(one, one);
|
||||
|
||||
{
|
||||
TimeZoneDetectorStatus two = new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING,
|
||||
ARBITRARY_TELEPHONY_ALGORITHM_STATUS, ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertEqualsAndHashCode(one, two);
|
||||
}
|
||||
|
||||
{
|
||||
TimeZoneDetectorStatus three = new TimeZoneDetectorStatus(DETECTOR_STATUS_NOT_RUNNING,
|
||||
ARBITRARY_TELEPHONY_ALGORITHM_STATUS, ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertNotEquals(one, three);
|
||||
assertNotEquals(three, one);
|
||||
}
|
||||
|
||||
{
|
||||
TelephonyTimeZoneAlgorithmStatus telephonyAlgorithmStatus =
|
||||
new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertNotEquals(telephonyAlgorithmStatus, ARBITRARY_TELEPHONY_ALGORITHM_STATUS);
|
||||
|
||||
TimeZoneDetectorStatus three = new TimeZoneDetectorStatus(DETECTOR_STATUS_NOT_RUNNING,
|
||||
telephonyAlgorithmStatus, ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertNotEquals(one, three);
|
||||
assertNotEquals(three, one);
|
||||
}
|
||||
|
||||
{
|
||||
LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
|
||||
LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY, null,
|
||||
LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY, null);
|
||||
assertNotEquals(locationAlgorithmStatus, ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
|
||||
TimeZoneDetectorStatus three = new TimeZoneDetectorStatus(DETECTOR_STATUS_NOT_RUNNING,
|
||||
ARBITRARY_TELEPHONY_ALGORITHM_STATUS, locationAlgorithmStatus);
|
||||
assertNotEquals(one, three);
|
||||
assertNotEquals(three, one);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
// Detector running.
|
||||
{
|
||||
TimeZoneDetectorStatus locationAlgorithmStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING, ARBITRARY_TELEPHONY_ALGORITHM_STATUS,
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
|
||||
// Detector not running.
|
||||
{
|
||||
TimeZoneDetectorStatus locationAlgorithmStatus =
|
||||
new TimeZoneDetectorStatus(DETECTOR_STATUS_NOT_RUNNING,
|
||||
ARBITRARY_TELEPHONY_ALGORITHM_STATUS,
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS);
|
||||
assertRoundTripParcelable(locationAlgorithmStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,20 +19,15 @@ package com.android.server.timezonedetector;
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* A time zone suggestion from the location_time_zone_manager service to the time_zone_detector
|
||||
* service.
|
||||
* A time zone suggestion from the location_time_zone_manager service (AKA the location-based time
|
||||
* zone detection algorithm).
|
||||
*
|
||||
* <p>Geolocation-based suggestions have the following properties:
|
||||
*
|
||||
@@ -63,24 +58,16 @@ import java.util.StringTokenizer;
|
||||
* location_time_zone_manager may become uncertain if components further downstream cannot
|
||||
* determine the device's location with sufficient accuracy, or if the location is known but no
|
||||
* time zone can be determined because no time zone mapping information is available.</li>
|
||||
* <li>{@code debugInfo} contains debugging metadata associated with the suggestion. This is
|
||||
* used to record why the suggestion exists and how it was obtained. This information exists
|
||||
* only to aid in debugging and therefore is used by {@link #toString()}, but it is not for use
|
||||
* in detection logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GeolocationTimeZoneSuggestion {
|
||||
|
||||
@ElapsedRealtimeLong private final long mEffectiveFromElapsedMillis;
|
||||
@Nullable private final List<String> mZoneIds;
|
||||
@Nullable private ArrayList<String> mDebugInfo;
|
||||
|
||||
private GeolocationTimeZoneSuggestion(
|
||||
@ElapsedRealtimeLong long effectiveFromElapsedMillis,
|
||||
@Nullable List<String> zoneIds) {
|
||||
@ElapsedRealtimeLong long effectiveFromElapsedMillis, @Nullable List<String> zoneIds) {
|
||||
mEffectiveFromElapsedMillis = effectiveFromElapsedMillis;
|
||||
if (zoneIds == null) {
|
||||
// Unopinionated
|
||||
@@ -104,8 +91,7 @@ public final class GeolocationTimeZoneSuggestion {
|
||||
*/
|
||||
@NonNull
|
||||
public static GeolocationTimeZoneSuggestion createCertainSuggestion(
|
||||
@ElapsedRealtimeLong long effectiveFromElapsedMillis,
|
||||
@NonNull List<String> zoneIds) {
|
||||
@ElapsedRealtimeLong long effectiveFromElapsedMillis, @NonNull List<String> zoneIds) {
|
||||
return new GeolocationTimeZoneSuggestion(effectiveFromElapsedMillis, zoneIds);
|
||||
}
|
||||
|
||||
@@ -126,25 +112,6 @@ public final class GeolocationTimeZoneSuggestion {
|
||||
return mZoneIds;
|
||||
}
|
||||
|
||||
/** Returns debug information. See {@link GeolocationTimeZoneSuggestion} for details. */
|
||||
@NonNull
|
||||
public List<String> getDebugInfo() {
|
||||
return mDebugInfo == null
|
||||
? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates information with the instance that can be useful for debugging / logging. The
|
||||
* information is present in {@link #toString()} but is not considered for
|
||||
* {@link #equals(Object)} and {@link #hashCode()}.
|
||||
*/
|
||||
public void addDebugInfo(String... debugInfos) {
|
||||
if (mDebugInfo == null) {
|
||||
mDebugInfo = new ArrayList<>();
|
||||
}
|
||||
mDebugInfo.addAll(Arrays.asList(debugInfos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@@ -169,59 +136,6 @@ public final class GeolocationTimeZoneSuggestion {
|
||||
return "GeolocationTimeZoneSuggestion{"
|
||||
+ "mEffectiveFromElapsedMillis=" + mEffectiveFromElapsedMillis
|
||||
+ ", mZoneIds=" + mZoneIds
|
||||
+ ", mDebugInfo=" + mDebugInfo
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static GeolocationTimeZoneSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) {
|
||||
String zoneIdsString = null;
|
||||
String opt;
|
||||
while ((opt = cmd.getNextArg()) != null) {
|
||||
switch (opt) {
|
||||
case "--zone_ids": {
|
||||
zoneIdsString = cmd.getNextArgRequired();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown option: " + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneIdsString == null) {
|
||||
throw new IllegalArgumentException("Missing --zone_ids");
|
||||
}
|
||||
|
||||
long elapsedRealtimeMillis = SystemClock.elapsedRealtime();
|
||||
List<String> zoneIds = parseZoneIdsArg(zoneIdsString);
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
new GeolocationTimeZoneSuggestion(elapsedRealtimeMillis, zoneIds);
|
||||
suggestion.addDebugInfo("Command line injection");
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
private static List<String> parseZoneIdsArg(String zoneIdsString) {
|
||||
if ("UNCERTAIN".equals(zoneIdsString)) {
|
||||
return null;
|
||||
} else if ("EMPTY".equals(zoneIdsString)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
ArrayList<String> zoneIds = new ArrayList<>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(zoneIdsString, ",");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
zoneIds.add(tokenizer.nextToken());
|
||||
}
|
||||
return zoneIds;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static void printCommandLineOpts(@NonNull PrintWriter pw) {
|
||||
pw.println("Geolocation suggestion options:");
|
||||
pw.println(" --zone_ids {UNCERTAIN|EMPTY|<Olson ID>+}");
|
||||
pw.println();
|
||||
pw.println("See " + GeolocationTimeZoneSuggestion.class.getName()
|
||||
+ " for more information");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* An event from the location_time_zone_manager service (AKA the location-based time zone detection
|
||||
* algorithm). An event can represent a new time zone recommendation, an algorithm status change, or
|
||||
* both.
|
||||
*
|
||||
* <p>Events have the following properties:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code algorithmStatus}: The current status of the location-based time zone detection
|
||||
* algorithm.</li>
|
||||
* <li>{@code suggestion}: The latest time zone suggestion, if there is one.</li>
|
||||
* <li>{@code debugInfo} contains debugging metadata associated with the suggestion. This is
|
||||
* used to record why the event exists and how information contained within it was obtained.
|
||||
* This information exists only to aid in debugging and therefore is used by
|
||||
* {@link #toString()}, but it is not for use in detection logic and is not considered in
|
||||
* {@link #hashCode()} or {@link #equals(Object)}.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class LocationAlgorithmEvent {
|
||||
|
||||
@NonNull private final LocationTimeZoneAlgorithmStatus mAlgorithmStatus;
|
||||
@Nullable private final GeolocationTimeZoneSuggestion mSuggestion;
|
||||
@Nullable private ArrayList<String> mDebugInfo;
|
||||
|
||||
/** Creates a new instance. */
|
||||
public LocationAlgorithmEvent(
|
||||
@NonNull LocationTimeZoneAlgorithmStatus algorithmStatus,
|
||||
@Nullable GeolocationTimeZoneSuggestion suggestion) {
|
||||
mAlgorithmStatus = Objects.requireNonNull(algorithmStatus);
|
||||
mSuggestion = suggestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the location time zone detector algorithm.
|
||||
*/
|
||||
@NonNull
|
||||
public LocationTimeZoneAlgorithmStatus getAlgorithmStatus() {
|
||||
return mAlgorithmStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest location algorithm suggestion. See {@link LocationAlgorithmEvent} for
|
||||
* details.
|
||||
*/
|
||||
@Nullable
|
||||
public GeolocationTimeZoneSuggestion getSuggestion() {
|
||||
return mSuggestion;
|
||||
}
|
||||
|
||||
/** Returns debug information. See {@link LocationAlgorithmEvent} for details. */
|
||||
@NonNull
|
||||
public List<String> getDebugInfo() {
|
||||
return mDebugInfo == null
|
||||
? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates information with the instance that can be useful for debugging / logging. The
|
||||
* information is present in {@link #toString()} but is not considered for
|
||||
* {@link #equals(Object)} and {@link #hashCode()}.
|
||||
*/
|
||||
public void addDebugInfo(String... debugInfos) {
|
||||
if (mDebugInfo == null) {
|
||||
mDebugInfo = new ArrayList<>();
|
||||
}
|
||||
mDebugInfo.addAll(Arrays.asList(debugInfos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LocationAlgorithmEvent that = (LocationAlgorithmEvent) o;
|
||||
return mAlgorithmStatus.equals(that.mAlgorithmStatus)
|
||||
&& Objects.equals(mSuggestion, that.mSuggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mAlgorithmStatus, mSuggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocationAlgorithmEvent{"
|
||||
+ "mAlgorithmStatus=" + mAlgorithmStatus
|
||||
+ ", mSuggestion=" + mSuggestion
|
||||
+ ", mDebugInfo=" + mDebugInfo
|
||||
+ '}';
|
||||
}
|
||||
|
||||
static LocationAlgorithmEvent parseCommandLineArg(@NonNull ShellCommand cmd) {
|
||||
String suggestionString = null;
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus = null;
|
||||
String opt;
|
||||
while ((opt = cmd.getNextArg()) != null) {
|
||||
switch (opt) {
|
||||
case "--status": {
|
||||
algorithmStatus = LocationTimeZoneAlgorithmStatus.parseCommandlineArg(
|
||||
cmd.getNextArgRequired());
|
||||
break;
|
||||
}
|
||||
case "--suggestion": {
|
||||
suggestionString = cmd.getNextArgRequired();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown option: " + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (algorithmStatus == null) {
|
||||
throw new IllegalArgumentException("Missing --status");
|
||||
}
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion = null;
|
||||
if (suggestionString != null) {
|
||||
List<String> zoneIds = parseZoneIds(suggestionString);
|
||||
long elapsedRealtimeMillis = SystemClock.elapsedRealtime();
|
||||
if (zoneIds == null) {
|
||||
suggestion = GeolocationTimeZoneSuggestion.createUncertainSuggestion(
|
||||
elapsedRealtimeMillis);
|
||||
} else {
|
||||
suggestion = GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
elapsedRealtimeMillis, zoneIds);
|
||||
}
|
||||
}
|
||||
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(algorithmStatus, suggestion);
|
||||
event.addDebugInfo("Command line injection");
|
||||
return event;
|
||||
}
|
||||
|
||||
private static List<String> parseZoneIds(String zoneIdsString) {
|
||||
if ("UNCERTAIN".equals(zoneIdsString)) {
|
||||
return null;
|
||||
} else if ("EMPTY".equals(zoneIdsString)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
ArrayList<String> zoneIds = new ArrayList<>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(zoneIdsString, ",");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
zoneIds.add(tokenizer.nextToken());
|
||||
}
|
||||
return zoneIds;
|
||||
}
|
||||
}
|
||||
|
||||
static void printCommandLineOpts(@NonNull PrintWriter pw) {
|
||||
pw.println("Location algorithm event options:");
|
||||
pw.println(" --status {LocationTimeZoneAlgorithmStatus toString() format}");
|
||||
pw.println(" [--suggestion {UNCERTAIN|EMPTY|<Olson ID>+}]");
|
||||
pw.println();
|
||||
pw.println("See " + LocationAlgorithmEvent.class.getName() + " for more information");
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ public final class MetricsTimeZoneDetectorState {
|
||||
@NonNull String deviceTimeZoneId,
|
||||
@Nullable ManualTimeZoneSuggestion latestManualSuggestion,
|
||||
@Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
|
||||
@Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
|
||||
@Nullable LocationAlgorithmEvent latestLocationAlgorithmEvent) {
|
||||
|
||||
boolean includeZoneIds = configurationInternal.isEnhancedMetricsCollectionEnabled();
|
||||
String metricDeviceTimeZoneId = includeZoneIds ? deviceTimeZoneId : null;
|
||||
@@ -101,9 +101,13 @@ public final class MetricsTimeZoneDetectorState {
|
||||
MetricsTimeZoneSuggestion latestCanonicalTelephonySuggestion =
|
||||
createMetricsTimeZoneSuggestion(
|
||||
tzIdOrdinalGenerator, latestTelephonySuggestion, includeZoneIds);
|
||||
MetricsTimeZoneSuggestion latestCanonicalGeolocationSuggestion =
|
||||
createMetricsTimeZoneSuggestion(
|
||||
tzIdOrdinalGenerator, latestGeolocationSuggestion, includeZoneIds);
|
||||
|
||||
MetricsTimeZoneSuggestion latestCanonicalGeolocationSuggestion = null;
|
||||
if (latestLocationAlgorithmEvent != null) {
|
||||
GeolocationTimeZoneSuggestion suggestion = latestLocationAlgorithmEvent.getSuggestion();
|
||||
latestCanonicalGeolocationSuggestion = createMetricsTimeZoneSuggestion(
|
||||
tzIdOrdinalGenerator, suggestion, includeZoneIds);
|
||||
}
|
||||
|
||||
return new MetricsTimeZoneDetectorState(
|
||||
configurationInternal, deviceTimeZoneIdOrdinal, metricDeviceTimeZoneId,
|
||||
|
||||
@@ -59,11 +59,11 @@ public interface TimeZoneDetectorInternal {
|
||||
boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion);
|
||||
|
||||
/**
|
||||
* Suggests the current time zone, determined using geolocation, to the detector. The
|
||||
* detector may ignore the signal based on system settings, whether better information is
|
||||
* available, and so on. This method may be implemented asynchronously.
|
||||
* Handles the supplied {@link LocationAlgorithmEvent}. The detector may ignore the event based
|
||||
* on system settings, whether better information is available, and so on. This method may be
|
||||
* implemented asynchronously.
|
||||
*/
|
||||
void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion);
|
||||
void handleLocationAlgorithmEvent(@NonNull LocationAlgorithmEvent locationAlgorithmEvent);
|
||||
|
||||
/** Generates a state snapshot for metrics. */
|
||||
@NonNull
|
||||
|
||||
@@ -76,13 +76,14 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGeolocationTimeZone(
|
||||
@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
|
||||
Objects.requireNonNull(timeZoneSuggestion);
|
||||
public void handleLocationAlgorithmEvent(
|
||||
@NonNull LocationAlgorithmEvent locationAlgorithmEvent) {
|
||||
Objects.requireNonNull(locationAlgorithmEvent);
|
||||
|
||||
// This call can take place on the mHandler thread because there is no return value.
|
||||
mHandler.post(
|
||||
() -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion));
|
||||
() -> mTimeZoneDetectorStrategy.handleLocationAlgorithmEvent(
|
||||
locationAlgorithmEvent));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -300,12 +300,13 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
}
|
||||
|
||||
/** Provided for command-line access. This is not exposed as a binder API. */
|
||||
void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
|
||||
void handleLocationAlgorithmEvent(@NonNull LocationAlgorithmEvent locationAlgorithmEvent) {
|
||||
enforceSuggestGeolocationTimeZonePermission();
|
||||
Objects.requireNonNull(timeZoneSuggestion);
|
||||
Objects.requireNonNull(locationAlgorithmEvent);
|
||||
|
||||
mHandler.post(
|
||||
() -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion));
|
||||
() -> mTimeZoneDetectorStrategy.handleLocationAlgorithmEvent(
|
||||
locationAlgorithmEvent));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_CONFIR
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_DUMP_METRICS;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_GET_TIME_ZONE_STATE;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_HANDLE_LOCATION_ALGORITHM_EVENT;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_ENABLED;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED;
|
||||
@@ -27,7 +28,6 @@ import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SERVIC
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_GEO_DETECTION_ENABLED;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_TIME_ZONE_STATE;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE;
|
||||
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
|
||||
@@ -79,8 +79,8 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
|
||||
return runIsGeoDetectionEnabled();
|
||||
case SHELL_COMMAND_SET_GEO_DETECTION_ENABLED:
|
||||
return runSetGeoDetectionEnabled();
|
||||
case SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE:
|
||||
return runSuggestGeolocationTimeZone();
|
||||
case SHELL_COMMAND_HANDLE_LOCATION_ALGORITHM_EVENT:
|
||||
return runHandleLocationEvent();
|
||||
case SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE:
|
||||
return runSuggestManualTimeZone();
|
||||
case SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE:
|
||||
@@ -153,34 +153,34 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
|
||||
return mInterface.updateConfiguration(userId, configuration) ? 0 : 1;
|
||||
}
|
||||
|
||||
private int runSuggestGeolocationTimeZone() {
|
||||
return runSuggestTimeZone(
|
||||
() -> GeolocationTimeZoneSuggestion.parseCommandLineArg(this),
|
||||
mInterface::suggestGeolocationTimeZone);
|
||||
private int runHandleLocationEvent() {
|
||||
return runSingleArgMethod(
|
||||
() -> LocationAlgorithmEvent.parseCommandLineArg(this),
|
||||
mInterface::handleLocationAlgorithmEvent);
|
||||
}
|
||||
|
||||
private int runSuggestManualTimeZone() {
|
||||
return runSuggestTimeZone(
|
||||
return runSingleArgMethod(
|
||||
() -> ManualTimeZoneSuggestion.parseCommandLineArg(this),
|
||||
mInterface::suggestManualTimeZone);
|
||||
}
|
||||
|
||||
private int runSuggestTelephonyTimeZone() {
|
||||
return runSuggestTimeZone(
|
||||
return runSingleArgMethod(
|
||||
() -> TelephonyTimeZoneSuggestion.parseCommandLineArg(this),
|
||||
mInterface::suggestTelephonyTimeZone);
|
||||
}
|
||||
|
||||
private <T> int runSuggestTimeZone(Supplier<T> suggestionParser, Consumer<T> invoker) {
|
||||
private <T> int runSingleArgMethod(Supplier<T> argParser, Consumer<T> invoker) {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
try {
|
||||
T suggestion = suggestionParser.get();
|
||||
if (suggestion == null) {
|
||||
pw.println("Error: suggestion not specified");
|
||||
T arg = argParser.get();
|
||||
if (arg == null) {
|
||||
pw.println("Error: arg not specified");
|
||||
return 1;
|
||||
}
|
||||
invoker.accept(suggestion);
|
||||
pw.println("Suggestion " + suggestion + " injected.");
|
||||
invoker.accept(arg);
|
||||
pw.println("Arg " + arg + " injected.");
|
||||
return 0;
|
||||
} catch (RuntimeException e) {
|
||||
pw.println(e);
|
||||
@@ -263,18 +263,18 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
|
||||
pw.printf(" Sets the geolocation time zone detection enabled setting.\n");
|
||||
pw.printf(" %s\n", SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK);
|
||||
pw.printf(" Signals that telephony time zone detection fall back can be used if"
|
||||
+ " geolocation detection is supported and enabled. This is a temporary state until"
|
||||
+ " geolocation detection becomes \"certain\". To have an effect this requires that"
|
||||
+ " the telephony fallback feature is supported on the device, see below for"
|
||||
+ " for device_config flags.\n");
|
||||
pw.println();
|
||||
pw.printf(" %s <geolocation suggestion opts>\n",
|
||||
SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE);
|
||||
pw.printf(" Suggests a time zone as if via the \"location\" origin.\n");
|
||||
+ " geolocation detection is supported and enabled.\n)");
|
||||
pw.printf(" This is a temporary state until geolocation detection becomes \"certain\"."
|
||||
+ "\n");
|
||||
pw.printf(" To have an effect this requires that the telephony fallback feature is"
|
||||
+ " supported on the device, see below for device_config flags.\n");
|
||||
pw.printf(" %s <location event opts>\n", SHELL_COMMAND_HANDLE_LOCATION_ALGORITHM_EVENT);
|
||||
pw.printf(" Simulates an event from the location time zone detection algorithm.\n");
|
||||
pw.printf(" %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE);
|
||||
pw.printf(" Suggests a time zone as if via the \"manual\" origin.\n");
|
||||
pw.printf(" Suggests a time zone as if supplied by a user manually.\n");
|
||||
pw.printf(" %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE);
|
||||
pw.printf(" Suggests a time zone as if via the \"telephony\" origin.\n");
|
||||
pw.printf(" Simulates a time zone suggestion from the telephony time zone detection"
|
||||
+ " algorithm.\n");
|
||||
pw.printf(" %s\n", SHELL_COMMAND_GET_TIME_ZONE_STATE);
|
||||
pw.printf(" Returns the current time zone setting state.\n");
|
||||
pw.printf(" %s <time zone state options>\n", SHELL_COMMAND_SET_TIME_ZONE_STATE);
|
||||
@@ -284,7 +284,7 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
|
||||
pw.printf(" %s\n", SHELL_COMMAND_DUMP_METRICS);
|
||||
pw.printf(" Dumps the service metrics to stdout for inspection.\n");
|
||||
pw.println();
|
||||
GeolocationTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
LocationAlgorithmEvent.printCommandLineOpts(pw);
|
||||
pw.println();
|
||||
ManualTimeZoneSuggestion.printCommandLineOpts(pw);
|
||||
pw.println();
|
||||
|
||||
@@ -157,10 +157,9 @@ public interface TimeZoneDetectorStrategy extends Dumpable {
|
||||
boolean confirmTimeZone(@NonNull String timeZoneId);
|
||||
|
||||
/**
|
||||
* Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
|
||||
* {@link GeolocationTimeZoneSuggestion#getZoneIds()} is {@code null}.
|
||||
* Handles an event from the location-based time zone detection algorithm.
|
||||
*/
|
||||
void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion suggestion);
|
||||
void handleLocationAlgorithmEvent(@NonNull LocationAlgorithmEvent event);
|
||||
|
||||
/**
|
||||
* Suggests a time zone for the device using manually-entered (i.e. user sourced) information.
|
||||
@@ -183,7 +182,7 @@ public interface TimeZoneDetectorStrategy extends Dumpable {
|
||||
|
||||
/**
|
||||
* Tells the strategy that it can fall back to telephony detection while geolocation detection
|
||||
* remains uncertain. {@link #suggestGeolocationTimeZone(GeolocationTimeZoneSuggestion)} can
|
||||
* remains uncertain. {@link #handleLocationAlgorithmEvent(LocationAlgorithmEvent)} can
|
||||
* disable it again. See {@link TimeZoneDetectorStrategy} for details.
|
||||
*/
|
||||
void enableTelephonyTimeZoneFallback();
|
||||
|
||||
@@ -29,9 +29,13 @@ import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.DetectorStatusTypes;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TelephonyTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TimeZoneCapabilities;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneDetectorStatus;
|
||||
import android.app.time.TimeZoneState;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
@@ -183,11 +187,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
|
||||
|
||||
/**
|
||||
* The latest geolocation suggestion received. If the user disabled geolocation time zone
|
||||
* detection then the latest suggestion is cleared.
|
||||
* The latest location algorithm event received.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private final ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
|
||||
private final ReferenceWithHistory<LocationAlgorithmEvent> mLatestLocationAlgorithmEvent =
|
||||
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
|
||||
|
||||
/**
|
||||
@@ -207,6 +210,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
@GuardedBy("this")
|
||||
@NonNull private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A snapshot of the current detector status. A local copy is cached because it is relatively
|
||||
* heavyweight to obtain and is used more often than it is expected to change.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
@NonNull
|
||||
private TimeZoneDetectorStatus mDetectorStatus;
|
||||
|
||||
/**
|
||||
* A snapshot of the current user's {@link ConfigurationInternal}. A local copy is cached
|
||||
* because it is relatively heavyweight to obtain and is used more often than it is expected to
|
||||
@@ -258,8 +269,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
// Listen for config and user changes and get an initial snapshot of configuration.
|
||||
StateChangeListener stateChangeListener = this::handleConfigurationInternalMaybeChanged;
|
||||
mServiceConfigAccessor.addConfigurationInternalChangeListener(stateChangeListener);
|
||||
mCurrentConfigurationInternal =
|
||||
mServiceConfigAccessor.getCurrentUserConfigurationInternal();
|
||||
|
||||
// Initialize mCurrentConfigurationInternal and mDetectorStatus with their starting
|
||||
// values.
|
||||
updateCurrentConfigurationInternalIfRequired("TimeZoneDetectorStrategyImpl:");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,6 +291,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
configurationInternal = mServiceConfigAccessor.getConfigurationInternal(userId);
|
||||
}
|
||||
return new TimeZoneCapabilitiesAndConfig(
|
||||
mDetectorStatus,
|
||||
configurationInternal.asCapabilities(bypassUserPolicyChecks),
|
||||
configurationInternal.asConfiguration());
|
||||
}
|
||||
@@ -295,28 +309,52 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
// but that could mean an immediate call to getCapabilitiesAndConfig() for the current user
|
||||
// wouldn't see the update. So, handle the cache update and notifications here. When the
|
||||
// async update listener triggers it will find everything already up to date and do nothing.
|
||||
if (updateSuccessful && mCurrentConfigurationInternal.getUserId() == userId) {
|
||||
ConfigurationInternal configurationInternal =
|
||||
mServiceConfigAccessor.getConfigurationInternal(userId);
|
||||
|
||||
// If the configuration actually changed, update the cached copy synchronously and do
|
||||
// other necessary house-keeping / (async) listener notifications.
|
||||
if (!configurationInternal.equals(mCurrentConfigurationInternal)) {
|
||||
mCurrentConfigurationInternal = configurationInternal;
|
||||
|
||||
String logMsg = "updateConfiguration:"
|
||||
+ " userId=" + userId
|
||||
+ ", configuration=" + configuration
|
||||
+ ", bypassUserPolicyChecks=" + bypassUserPolicyChecks
|
||||
+ ", mCurrentConfigurationInternal=" + mCurrentConfigurationInternal;
|
||||
logTimeZoneDebugInfo(logMsg);
|
||||
|
||||
handleConfigurationInternalChanged(logMsg);
|
||||
}
|
||||
if (updateSuccessful) {
|
||||
String logMsg = "updateConfiguration:"
|
||||
+ " userId=" + userId
|
||||
+ ", configuration=" + configuration
|
||||
+ ", bypassUserPolicyChecks=" + bypassUserPolicyChecks;
|
||||
updateCurrentConfigurationInternalIfRequired(logMsg);
|
||||
}
|
||||
return updateSuccessful;
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
private void updateCurrentConfigurationInternalIfRequired(@NonNull String logMsg) {
|
||||
ConfigurationInternal newCurrentConfigurationInternal =
|
||||
mServiceConfigAccessor.getCurrentUserConfigurationInternal();
|
||||
// mCurrentConfigurationInternal is null the first time this method is called.
|
||||
ConfigurationInternal oldCurrentConfigurationInternal = mCurrentConfigurationInternal;
|
||||
|
||||
// If the configuration actually changed, update the cached copy synchronously and do
|
||||
// other necessary house-keeping / (async) listener notifications.
|
||||
if (!newCurrentConfigurationInternal.equals(oldCurrentConfigurationInternal)) {
|
||||
mCurrentConfigurationInternal = newCurrentConfigurationInternal;
|
||||
|
||||
logMsg += " [oldConfiguration=" + oldCurrentConfigurationInternal
|
||||
+ ", newConfiguration=" + newCurrentConfigurationInternal
|
||||
+ "]";
|
||||
logTimeZoneDebugInfo(logMsg);
|
||||
|
||||
// ConfigurationInternal changes can affect the detector's status.
|
||||
updateDetectorStatus();
|
||||
|
||||
// The configuration and maybe the status changed so notify listeners.
|
||||
notifyStateChangeListenersAsynchronously();
|
||||
|
||||
// The configuration change may have changed available suggestions or the way
|
||||
// suggestions are used, so re-run detection.
|
||||
doAutoTimeZoneDetection(mCurrentConfigurationInternal, logMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
private void notifyStateChangeListenersAsynchronously() {
|
||||
for (StateChangeListener listener : mStateChangeListeners) {
|
||||
mStateChangeHandler.post(listener::onChange);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addChangeListener(StateChangeListener listener) {
|
||||
mStateChangeListeners.add(listener);
|
||||
@@ -356,33 +394,39 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void suggestGeolocationTimeZone(
|
||||
@NonNull GeolocationTimeZoneSuggestion suggestion) {
|
||||
|
||||
public synchronized void handleLocationAlgorithmEvent(@NonNull LocationAlgorithmEvent event) {
|
||||
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
|
||||
if (DBG) {
|
||||
Slog.d(LOG_TAG, "Geolocation suggestion received."
|
||||
Slog.d(LOG_TAG, "Location algorithm event received."
|
||||
+ " currentUserConfig=" + currentUserConfig
|
||||
+ " newSuggestion=" + suggestion);
|
||||
+ " event=" + event);
|
||||
}
|
||||
Objects.requireNonNull(suggestion);
|
||||
Objects.requireNonNull(event);
|
||||
|
||||
// Geolocation suggestions may be stored but not used during time zone detection if the
|
||||
// Location algorithm events may be stored but not used during time zone detection if the
|
||||
// configuration doesn't have geo time zone detection enabled. The caller is expected to
|
||||
// withdraw a previous suggestion (i.e. submit an "uncertain" suggestion, when geo time zone
|
||||
// detection is disabled.
|
||||
// withdraw a previous suggestion, i.e. submit an event containing an "uncertain"
|
||||
// suggestion, when geo time zone detection is disabled.
|
||||
|
||||
// The suggestion's "effective from" time is ignored: we currently assume suggestions
|
||||
// are made in a sensible order and the most recent is always the best one to use.
|
||||
mLatestGeoLocationSuggestion.set(suggestion);
|
||||
// We currently assume events are made in a sensible order and the most recent is always the
|
||||
// best one to use.
|
||||
mLatestLocationAlgorithmEvent.set(event);
|
||||
|
||||
// The latest location algorithm event can affect the cached detector status, so update it
|
||||
// and notify state change listeners as needed.
|
||||
boolean statusChanged = updateDetectorStatus();
|
||||
if (statusChanged) {
|
||||
notifyStateChangeListenersAsynchronously();
|
||||
}
|
||||
|
||||
// Update the mTelephonyTimeZoneFallbackEnabled state if needed: a certain suggestion
|
||||
// will usually disable telephony fallback mode if it is currently enabled.
|
||||
// TODO(b/236624675)Some provider status codes can be used to enable telephony fallback.
|
||||
disableTelephonyFallbackIfNeeded();
|
||||
|
||||
// Now perform auto time zone detection. The new suggestion may be used to modify the
|
||||
// time zone setting.
|
||||
String reason = "New geolocation time zone suggested. suggestion=" + suggestion;
|
||||
// Now perform auto time zone detection. The new event may be used to modify the time zone
|
||||
// setting.
|
||||
String reason = "New location algorithm event received. event=" + event;
|
||||
doAutoTimeZoneDetection(currentUserConfig, reason);
|
||||
}
|
||||
|
||||
@@ -465,9 +509,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
+ mTelephonyTimeZoneFallbackEnabled;
|
||||
logTimeZoneDebugInfo(logMsg);
|
||||
|
||||
// mTelephonyTimeZoneFallbackEnabled and mLatestGeoLocationSuggestion interact.
|
||||
// If there is currently a certain geolocation suggestion, then the telephony fallback
|
||||
// value needs to be considered after changing it.
|
||||
// mTelephonyTimeZoneFallbackEnabled and mLatestLocationAlgorithmEvent interact.
|
||||
// If the latest event contains a "certain" geolocation suggestion, then the telephony
|
||||
// fallback value needs to be considered after changing it.
|
||||
// With the way that the mTelephonyTimeZoneFallbackEnabled time is currently chosen
|
||||
// above, and the fact that geolocation suggestions should never have a time in the
|
||||
// future, the following call will be a no-op, and telephony fallback will remain
|
||||
@@ -507,7 +551,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
mEnvironment.getDeviceTimeZone(),
|
||||
getLatestManualSuggestion(),
|
||||
telephonySuggestion,
|
||||
getLatestGeolocationSuggestion());
|
||||
getLatestLocationAlgorithmEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -606,13 +650,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private boolean doGeolocationTimeZoneDetection(@NonNull String detectionReason) {
|
||||
GeolocationTimeZoneSuggestion latestGeolocationSuggestion =
|
||||
mLatestGeoLocationSuggestion.get();
|
||||
if (latestGeolocationSuggestion == null) {
|
||||
// Terminate early if there's nothing to do.
|
||||
LocationAlgorithmEvent latestLocationAlgorithmEvent = mLatestLocationAlgorithmEvent.get();
|
||||
if (latestLocationAlgorithmEvent == null
|
||||
|| latestLocationAlgorithmEvent.getSuggestion() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> zoneIds = latestGeolocationSuggestion.getZoneIds();
|
||||
GeolocationTimeZoneSuggestion suggestion = latestLocationAlgorithmEvent.getSuggestion();
|
||||
List<String> zoneIds = suggestion.getZoneIds();
|
||||
if (zoneIds == null) {
|
||||
// This means the originator of the suggestion is uncertain about the time zone. The
|
||||
// existing time zone setting must be left as it is but detection can go on looking for
|
||||
@@ -645,13 +691,18 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mTelephonyTimeZoneFallbackEnabled state to {@code false} if the latest geo
|
||||
* suggestion is a "certain" suggestion that comes after the time when telephony fallback was
|
||||
* enabled.
|
||||
* Sets the mTelephonyTimeZoneFallbackEnabled state to {@code false} if the latest location
|
||||
* algorithm event contains a "certain" suggestion that comes after the time when telephony
|
||||
* fallback was enabled.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private void disableTelephonyFallbackIfNeeded() {
|
||||
GeolocationTimeZoneSuggestion suggestion = mLatestGeoLocationSuggestion.get();
|
||||
LocationAlgorithmEvent latestLocationAlgorithmEvent = mLatestLocationAlgorithmEvent.get();
|
||||
if (latestLocationAlgorithmEvent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion = latestLocationAlgorithmEvent.getSuggestion();
|
||||
boolean isLatestSuggestionCertain = suggestion != null && suggestion.getZoneIds() != null;
|
||||
if (isLatestSuggestionCertain && mTelephonyTimeZoneFallbackEnabled.getValue()) {
|
||||
// This transition ONLY changes mTelephonyTimeZoneFallbackEnabled from
|
||||
@@ -809,33 +860,27 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* Handles a configuration change notification.
|
||||
*/
|
||||
private synchronized void handleConfigurationInternalMaybeChanged() {
|
||||
ConfigurationInternal currentUserConfig =
|
||||
mServiceConfigAccessor.getCurrentUserConfigurationInternal();
|
||||
|
||||
// The configuration may not actually have changed so check before doing anything.
|
||||
if (!currentUserConfig.equals(mCurrentConfigurationInternal)) {
|
||||
String logMsg = "handleConfigurationInternalMaybeChanged:"
|
||||
+ " oldConfiguration=" + mCurrentConfigurationInternal
|
||||
+ ", newConfiguration=" + currentUserConfig;
|
||||
logTimeZoneDebugInfo(logMsg);
|
||||
|
||||
mCurrentConfigurationInternal = currentUserConfig;
|
||||
|
||||
handleConfigurationInternalChanged(logMsg);
|
||||
}
|
||||
String logMsg = "handleConfigurationInternalMaybeChanged:";
|
||||
updateCurrentConfigurationInternalIfRequired(logMsg);
|
||||
}
|
||||
|
||||
/** House-keeping that needs to be done when the mCurrentConfigurationInternal has changed. */
|
||||
/**
|
||||
* Called whenever the information that contributes to {@link #mDetectorStatus} could have
|
||||
* changed. Updates the cached status snapshot if required.
|
||||
*
|
||||
* @return true if the status had changed and has been updated
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private void handleConfigurationInternalChanged(@NonNull String logMsg) {
|
||||
// Notify change listeners asynchronously.
|
||||
for (StateChangeListener listener : mStateChangeListeners) {
|
||||
mStateChangeHandler.post(listener::onChange);
|
||||
private boolean updateDetectorStatus() {
|
||||
TimeZoneDetectorStatus newDetectorStatus = createTimeZoneDetectorStatus(
|
||||
mCurrentConfigurationInternal, mLatestLocationAlgorithmEvent.get());
|
||||
// mDetectorStatus is null the first time this method is called.
|
||||
TimeZoneDetectorStatus oldDetectorStatus = mDetectorStatus;
|
||||
boolean statusChanged = !newDetectorStatus.equals(oldDetectorStatus);
|
||||
if (statusChanged) {
|
||||
mDetectorStatus = newDetectorStatus;
|
||||
}
|
||||
|
||||
// The configuration change may have changed available suggestions or the way
|
||||
// suggestions are used, so re-run detection.
|
||||
doAutoTimeZoneDetection(mCurrentConfigurationInternal, logMsg);
|
||||
return statusChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -847,6 +892,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
|
||||
ipw.increaseIndent(); // level 1
|
||||
ipw.println("mCurrentConfigurationInternal=" + mCurrentConfigurationInternal);
|
||||
ipw.println("mDetectorStatus=" + mDetectorStatus);
|
||||
final boolean bypassUserPolicyChecks = false;
|
||||
ipw.println("[Capabilities="
|
||||
+ mCurrentConfigurationInternal.asCapabilities(bypassUserPolicyChecks) + "]");
|
||||
@@ -870,9 +916,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
mLatestManualSuggestion.dump(ipw);
|
||||
ipw.decreaseIndent(); // level 2
|
||||
|
||||
ipw.println("Geolocation suggestion history:");
|
||||
ipw.println("Location algorithm event history:");
|
||||
ipw.increaseIndent(); // level 2
|
||||
mLatestGeoLocationSuggestion.dump(ipw);
|
||||
mLatestLocationAlgorithmEvent.dump(ipw);
|
||||
ipw.decreaseIndent(); // level 2
|
||||
|
||||
ipw.println("Telephony suggestion history:");
|
||||
@@ -886,6 +932,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* A method used to inspect strategy state during tests. Not intended for general use.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public synchronized ManualTimeZoneSuggestion getLatestManualSuggestion() {
|
||||
return mLatestManualSuggestion.get();
|
||||
}
|
||||
@@ -894,6 +941,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* A method used to inspect strategy state during tests. Not intended for general use.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public synchronized QualifiedTelephonyTimeZoneSuggestion getLatestTelephonySuggestion(
|
||||
int slotIndex) {
|
||||
return mTelephonySuggestionsBySlotIndex.get(slotIndex);
|
||||
@@ -903,8 +951,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* A method used to inspect strategy state during tests. Not intended for general use.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public synchronized GeolocationTimeZoneSuggestion getLatestGeolocationSuggestion() {
|
||||
return mLatestGeoLocationSuggestion.get();
|
||||
@Nullable
|
||||
public synchronized LocationAlgorithmEvent getLatestLocationAlgorithmEvent() {
|
||||
return mLatestLocationAlgorithmEvent.get();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -917,6 +966,11 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
return mCurrentConfigurationInternal;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public synchronized TimeZoneDetectorStatus getCachedDetectorStatusForTests() {
|
||||
return mDetectorStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link TelephonyTimeZoneSuggestion} with additional qualifying metadata.
|
||||
*/
|
||||
@@ -970,4 +1024,42 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
private static String formatDebugString(TimestampedValue<?> value) {
|
||||
return value.getValue() + " @ " + Duration.ofMillis(value.getReferenceTimeMillis());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static TimeZoneDetectorStatus createTimeZoneDetectorStatus(
|
||||
@NonNull ConfigurationInternal currentConfigurationInternal,
|
||||
@Nullable LocationAlgorithmEvent latestLocationAlgorithmEvent) {
|
||||
|
||||
int detectorStatus;
|
||||
if (!currentConfigurationInternal.isAutoDetectionSupported()) {
|
||||
detectorStatus = DetectorStatusTypes.DETECTOR_STATUS_NOT_SUPPORTED;
|
||||
} else if (currentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
|
||||
detectorStatus = DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
} else {
|
||||
detectorStatus = DetectorStatusTypes.DETECTOR_STATUS_NOT_RUNNING;
|
||||
}
|
||||
|
||||
TelephonyTimeZoneAlgorithmStatus telephonyAlgorithmStatus =
|
||||
createTelephonyAlgorithmStatus(currentConfigurationInternal);
|
||||
|
||||
LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
|
||||
latestLocationAlgorithmEvent == null ? LocationTimeZoneAlgorithmStatus.UNKNOWN
|
||||
: latestLocationAlgorithmEvent.getAlgorithmStatus();
|
||||
|
||||
return new TimeZoneDetectorStatus(
|
||||
detectorStatus, telephonyAlgorithmStatus, locationAlgorithmStatus);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static TelephonyTimeZoneAlgorithmStatus createTelephonyAlgorithmStatus(
|
||||
@NonNull ConfigurationInternal currentConfigurationInternal) {
|
||||
int algorithmStatus;
|
||||
if (!currentConfigurationInternal.isTelephonyDetectionSupported()) {
|
||||
algorithmStatus = DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
|
||||
} else {
|
||||
// The telephony detector is passive, so we treat it as "running".
|
||||
algorithmStatus = DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
}
|
||||
return new TelephonyTimeZoneAlgorithmStatus(algorithmStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.android.server.timezonedetector.location;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
import com.android.server.timezonedetector.LocationAlgorithmEvent;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProviderController.State;
|
||||
|
||||
@@ -32,14 +32,14 @@ import java.util.Objects;
|
||||
final class LocationTimeZoneManagerServiceState {
|
||||
|
||||
private final @State String mControllerState;
|
||||
@Nullable private final GeolocationTimeZoneSuggestion mLastSuggestion;
|
||||
@Nullable private final LocationAlgorithmEvent mLastEvent;
|
||||
@NonNull private final List<@State String> mControllerStates;
|
||||
@NonNull private final List<ProviderState> mPrimaryProviderStates;
|
||||
@NonNull private final List<ProviderState> mSecondaryProviderStates;
|
||||
|
||||
LocationTimeZoneManagerServiceState(@NonNull Builder builder) {
|
||||
mControllerState = builder.mControllerState;
|
||||
mLastSuggestion = builder.mLastSuggestion;
|
||||
mLastEvent = builder.mLastEvent;
|
||||
mControllerStates = Objects.requireNonNull(builder.mControllerStates);
|
||||
mPrimaryProviderStates = Objects.requireNonNull(builder.mPrimaryProviderStates);
|
||||
mSecondaryProviderStates = Objects.requireNonNull(builder.mSecondaryProviderStates);
|
||||
@@ -50,8 +50,8 @@ final class LocationTimeZoneManagerServiceState {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GeolocationTimeZoneSuggestion getLastSuggestion() {
|
||||
return mLastSuggestion;
|
||||
public LocationAlgorithmEvent getLastEvent() {
|
||||
return mLastEvent;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -73,7 +73,7 @@ final class LocationTimeZoneManagerServiceState {
|
||||
public String toString() {
|
||||
return "LocationTimeZoneManagerServiceState{"
|
||||
+ "mControllerState=" + mControllerState
|
||||
+ ", mLastSuggestion=" + mLastSuggestion
|
||||
+ ", mLastEvent=" + mLastEvent
|
||||
+ ", mControllerStates=" + mControllerStates
|
||||
+ ", mPrimaryProviderStates=" + mPrimaryProviderStates
|
||||
+ ", mSecondaryProviderStates=" + mSecondaryProviderStates
|
||||
@@ -83,7 +83,7 @@ final class LocationTimeZoneManagerServiceState {
|
||||
static final class Builder {
|
||||
|
||||
private @State String mControllerState;
|
||||
private GeolocationTimeZoneSuggestion mLastSuggestion;
|
||||
private LocationAlgorithmEvent mLastEvent;
|
||||
private List<@State String> mControllerStates;
|
||||
private List<ProviderState> mPrimaryProviderStates;
|
||||
private List<ProviderState> mSecondaryProviderStates;
|
||||
@@ -95,8 +95,8 @@ final class LocationTimeZoneManagerServiceState {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Builder setLastSuggestion(@NonNull GeolocationTimeZoneSuggestion lastSuggestion) {
|
||||
mLastSuggestion = Objects.requireNonNull(lastSuggestion);
|
||||
Builder setLastEvent(@NonNull LocationAlgorithmEvent lastEvent) {
|
||||
mLastEvent = Objects.requireNonNull(lastEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.android.server.timezonedetector.location;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
|
||||
import static android.app.time.LocationTimeZoneManager.NULL_PACKAGE_NAME_TOKEN;
|
||||
import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
|
||||
@@ -51,9 +55,14 @@ import static com.android.server.timezonedetector.location.LocationTimeZoneProvi
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.app.time.GeolocationTimeZoneSuggestionProto;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatusProto;
|
||||
import android.app.time.LocationTimeZoneManagerProto;
|
||||
import android.app.time.LocationTimeZoneManagerServiceStateProto;
|
||||
import android.app.time.LocationTimeZoneProviderEventProto;
|
||||
import android.app.time.TimeZoneDetectorProto;
|
||||
import android.app.time.TimeZoneProviderStateProto;
|
||||
import android.app.timezonedetector.TimeZoneDetector;
|
||||
import android.os.ShellCommand;
|
||||
@@ -62,6 +71,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.util.dump.DualDumpOutputStream;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
import com.android.server.timezonedetector.LocationAlgorithmEvent;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProviderController.State;
|
||||
|
||||
@@ -239,19 +249,39 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand {
|
||||
outputStream = new DualDumpOutputStream(
|
||||
new IndentingPrintWriter(getOutPrintWriter(), " "));
|
||||
}
|
||||
if (state.getLastSuggestion() != null) {
|
||||
GeolocationTimeZoneSuggestion lastSuggestion = state.getLastSuggestion();
|
||||
long lastSuggestionToken = outputStream.start(
|
||||
"last_suggestion", LocationTimeZoneManagerServiceStateProto.LAST_SUGGESTION);
|
||||
for (String zoneId : lastSuggestion.getZoneIds()) {
|
||||
outputStream.write(
|
||||
"zone_ids" , GeolocationTimeZoneSuggestionProto.ZONE_IDS, zoneId);
|
||||
|
||||
if (state.getLastEvent() != null) {
|
||||
LocationAlgorithmEvent lastEvent = state.getLastEvent();
|
||||
long lastEventToken = outputStream.start(
|
||||
"last_event", LocationTimeZoneManagerServiceStateProto.LAST_EVENT);
|
||||
|
||||
// lastEvent.algorithmStatus
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus = lastEvent.getAlgorithmStatus();
|
||||
long algorithmStatusToken = outputStream.start(
|
||||
"algorithm_status", LocationTimeZoneProviderEventProto.ALGORITHM_STATUS);
|
||||
outputStream.write("status", LocationTimeZoneAlgorithmStatusProto.STATUS,
|
||||
convertDetectionAlgorithmStatusToEnumToProtoEnum(algorithmStatus.getStatus()));
|
||||
outputStream.end(algorithmStatusToken);
|
||||
|
||||
// lastEvent.suggestion
|
||||
if (lastEvent.getSuggestion() != null) {
|
||||
long suggestionToken = outputStream.start(
|
||||
"suggestion", LocationTimeZoneProviderEventProto.SUGGESTION);
|
||||
GeolocationTimeZoneSuggestion lastSuggestion = lastEvent.getSuggestion();
|
||||
for (String zoneId : lastSuggestion.getZoneIds()) {
|
||||
outputStream.write(
|
||||
"zone_ids", GeolocationTimeZoneSuggestionProto.ZONE_IDS, zoneId);
|
||||
}
|
||||
outputStream.end(suggestionToken);
|
||||
}
|
||||
for (String debugInfo : lastSuggestion.getDebugInfo()) {
|
||||
|
||||
// lastEvent.debugInfo
|
||||
for (String debugInfo : lastEvent.getDebugInfo()) {
|
||||
outputStream.write(
|
||||
"debug_info", GeolocationTimeZoneSuggestionProto.DEBUG_INFO, debugInfo);
|
||||
"debug_info", LocationTimeZoneProviderEventProto.DEBUG_INFO, debugInfo);
|
||||
}
|
||||
outputStream.end(lastSuggestionToken);
|
||||
|
||||
outputStream.end(lastEventToken);
|
||||
}
|
||||
|
||||
writeControllerStates(outputStream, state.getControllerStates());
|
||||
@@ -330,6 +360,22 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private static int convertDetectionAlgorithmStatusToEnumToProtoEnum(
|
||||
@DetectionAlgorithmStatus int statusEnum) {
|
||||
switch (statusEnum) {
|
||||
case DETECTION_ALGORITHM_STATUS_UNKNOWN:
|
||||
return TimeZoneDetectorProto.DETECTION_ALGORITHM_STATUS_UNKNOWN;
|
||||
case DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED:
|
||||
return TimeZoneDetectorProto.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
|
||||
case DETECTION_ALGORITHM_STATUS_NOT_RUNNING:
|
||||
return TimeZoneDetectorProto.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
case DETECTION_ALGORITHM_STATUS_RUNNING:
|
||||
return TimeZoneDetectorProto.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown statusEnum=" + statusEnum);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportError(@NonNull Throwable e) {
|
||||
PrintWriter errPrintWriter = getErrPrintWriter();
|
||||
errPrintWriter.println("Error: ");
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.timezonedetector.location;
|
||||
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
|
||||
import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_PERMANENT_FAILURE;
|
||||
import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_SUGGESTION;
|
||||
import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
|
||||
@@ -33,6 +37,7 @@ import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus.ProviderStatus;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.service.timezone.TimeZoneProviderEvent;
|
||||
@@ -295,6 +300,34 @@ abstract class LocationTimeZoneProvider implements Dumpable {
|
||||
|| stateEnum == PROVIDER_STATE_DESTROYED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the internal state enum value to one of the status values exposed to the layers
|
||||
* above.
|
||||
*/
|
||||
public @ProviderStatus int getProviderStatus() {
|
||||
switch (stateEnum) {
|
||||
case PROVIDER_STATE_STARTED_INITIALIZING:
|
||||
return PROVIDER_STATUS_NOT_READY;
|
||||
case PROVIDER_STATE_STARTED_CERTAIN:
|
||||
return PROVIDER_STATUS_IS_CERTAIN;
|
||||
case PROVIDER_STATE_STARTED_UNCERTAIN:
|
||||
return PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
case PROVIDER_STATE_PERM_FAILED:
|
||||
// Perm failed means the providers wasn't configured, configured properly,
|
||||
// or has removed itself for other reasons, e.g. turned-down server.
|
||||
return PROVIDER_STATUS_NOT_PRESENT;
|
||||
case PROVIDER_STATE_STOPPED:
|
||||
case PROVIDER_STATE_DESTROYED:
|
||||
// This is a "safe" default that best describes a provider that isn't in one of
|
||||
// the more obviously mapped states.
|
||||
return PROVIDER_STATUS_NOT_READY;
|
||||
case PROVIDER_STATE_UNKNOWN:
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Unknown state enum:" + prettyPrintStateEnum(stateEnum));
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the status reported by the provider, if available. */
|
||||
@Nullable
|
||||
TimeZoneProviderStatus getReportedStatus() {
|
||||
|
||||
@@ -35,6 +35,10 @@ import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringDef;
|
||||
import android.app.time.DetectorStatusTypes;
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus.ProviderStatus;
|
||||
import android.service.timezone.TimeZoneProviderEvent;
|
||||
import android.service.timezone.TimeZoneProviderSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
@@ -44,6 +48,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.timezonedetector.ConfigurationInternal;
|
||||
import com.android.server.timezonedetector.Dumpable;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
import com.android.server.timezonedetector.LocationAlgorithmEvent;
|
||||
import com.android.server.timezonedetector.ReferenceWithHistory;
|
||||
import com.android.server.timezonedetector.location.ThreadingDomain.SingleRunnableQueue;
|
||||
|
||||
@@ -83,8 +88,7 @@ import java.util.Objects;
|
||||
* <p>All incoming calls except for {@link
|
||||
* LocationTimeZoneProviderController#dump(android.util.IndentingPrintWriter, String[])} must be
|
||||
* made on the {@link android.os.Handler} thread of the {@link ThreadingDomain} passed to {@link
|
||||
* #LocationTimeZoneProviderController(ThreadingDomain, LocationTimeZoneProvider,
|
||||
* LocationTimeZoneProvider)}.
|
||||
* #LocationTimeZoneProviderController}.
|
||||
*
|
||||
* <p>Provider / controller integration notes:
|
||||
*
|
||||
@@ -172,10 +176,10 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
@GuardedBy("mSharedLock")
|
||||
private final ReferenceWithHistory<@State String> mState = new ReferenceWithHistory<>(10);
|
||||
|
||||
/** Contains the last suggestion actually made, if there is one. */
|
||||
/** Contains the last event reported, if there is one. */
|
||||
@GuardedBy("mSharedLock")
|
||||
@Nullable
|
||||
private GeolocationTimeZoneSuggestion mLastSuggestion;
|
||||
private LocationAlgorithmEvent mLastEvent;
|
||||
|
||||
LocationTimeZoneProviderController(@NonNull ThreadingDomain threadingDomain,
|
||||
@NonNull MetricsLogger metricsLogger,
|
||||
@@ -213,7 +217,7 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
setState(STATE_PROVIDERS_INITIALIZING);
|
||||
mPrimaryProvider.initialize(providerListener);
|
||||
mSecondaryProvider.initialize(providerListener);
|
||||
setState(STATE_STOPPED);
|
||||
setStateAndReportStatusOnlyEvent(STATE_STOPPED, "initialize()");
|
||||
|
||||
alterProvidersStartedStateIfRequired(
|
||||
null /* oldConfiguration */, mCurrentUserConfiguration);
|
||||
@@ -273,13 +277,51 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
// Enter destroyed state.
|
||||
mPrimaryProvider.destroy();
|
||||
mSecondaryProvider.destroy();
|
||||
setState(STATE_DESTROYED);
|
||||
setStateAndReportStatusOnlyEvent(STATE_DESTROYED, "destroy()");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates {@link #mState} if needed, and performs all the record-keeping / callbacks associated
|
||||
* with state changes.
|
||||
* Sets the state and reports an event containing the algorithm status and a {@code null}
|
||||
* suggestion.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void setStateAndReportStatusOnlyEvent(@State String state, @NonNull String reason) {
|
||||
setState(state);
|
||||
|
||||
final GeolocationTimeZoneSuggestion suggestion = null;
|
||||
LocationAlgorithmEvent event =
|
||||
new LocationAlgorithmEvent(generateCurrentAlgorithmStatus(), suggestion);
|
||||
event.addDebugInfo(reason);
|
||||
reportEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an event containing the algorithm status and the supplied suggestion.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void reportSuggestionEvent(
|
||||
@NonNull GeolocationTimeZoneSuggestion suggestion, @NonNull String reason) {
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus = generateCurrentAlgorithmStatus();
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
algorithmStatus, suggestion);
|
||||
event.addDebugInfo(reason);
|
||||
reportEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an event immediately. This method updates {@link #mLastEvent}.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void reportEvent(@NonNull LocationAlgorithmEvent event) {
|
||||
debugLog("makeSuggestion: suggestion=" + event);
|
||||
mCallback.sendEvent(event);
|
||||
mLastEvent = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state if needed. This includes setting {@link #mState} and performing all the
|
||||
* record-keeping / callbacks associated with state changes.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void setState(@State String state) {
|
||||
@@ -300,17 +342,7 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
// By definition, if both providers are stopped, the controller is uncertain.
|
||||
cancelUncertaintyTimeout();
|
||||
|
||||
// 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 providers are
|
||||
// re-started).
|
||||
if (Objects.equals(mState.get(), STATE_CERTAIN)) {
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
mEnvironment.elapsedRealtimeMillis(),
|
||||
"Withdraw previous suggestion, providers are stopping: " + reason);
|
||||
makeSuggestion(suggestion, STATE_UNCERTAIN);
|
||||
}
|
||||
setState(STATE_STOPPED);
|
||||
setStateAndReportStatusOnlyEvent(STATE_STOPPED, "Providers stopped: " + reason);
|
||||
}
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
@@ -381,7 +413,7 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
// timeout started when the primary entered {started uncertain} should be cancelled.
|
||||
|
||||
if (newIsGeoDetectionExecutionEnabled) {
|
||||
setState(STATE_INITIALIZING);
|
||||
setStateAndReportStatusOnlyEvent(STATE_INITIALIZING, "initializing()");
|
||||
|
||||
// Try to start the primary provider.
|
||||
tryStartProvider(mPrimaryProvider, newConfiguration);
|
||||
@@ -397,13 +429,11 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
|
||||
if (!newSecondaryState.isStarted()) {
|
||||
// If both providers are {perm failed} then the controller immediately
|
||||
// reports uncertain.
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
mEnvironment.elapsedRealtimeMillis(),
|
||||
"Providers are failed:"
|
||||
+ " primary=" + mPrimaryProvider.getCurrentState()
|
||||
+ " secondary=" + mPrimaryProvider.getCurrentState());
|
||||
makeSuggestion(suggestion, STATE_FAILED);
|
||||
// reports the failure.
|
||||
String reason = "Providers are failed:"
|
||||
+ " primary=" + mPrimaryProvider.getCurrentState()
|
||||
+ " secondary=" + mPrimaryProvider.getCurrentState();
|
||||
setStateAndReportStatusOnlyEvent(STATE_FAILED, reason);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -537,12 +567,10 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
|
||||
// If both providers are now terminated, then a suggestion must be sent informing the
|
||||
// time zone detector that there are no further updates coming in the future.
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
mEnvironment.elapsedRealtimeMillis(),
|
||||
"Both providers are terminated:"
|
||||
+ " primary=" + primaryCurrentState.provider
|
||||
+ ", secondary=" + secondaryCurrentState.provider);
|
||||
makeSuggestion(suggestion, STATE_FAILED);
|
||||
String reason = "Both providers are terminated:"
|
||||
+ " primary=" + primaryCurrentState.provider
|
||||
+ ", secondary=" + secondaryCurrentState.provider;
|
||||
setStateAndReportStatusOnlyEvent(STATE_FAILED, reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,6 +643,9 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
|
||||
TimeZoneProviderSuggestion providerSuggestion = providerEvent.getSuggestion();
|
||||
|
||||
// Set the current state so it is correct when the suggestion event is created.
|
||||
setState(STATE_CERTAIN);
|
||||
|
||||
// For the suggestion's effectiveFromElapsedMillis, use the time embedded in the provider's
|
||||
// suggestion (which indicates the time when the provider detected the location used to
|
||||
// establish the time zone).
|
||||
@@ -623,15 +654,13 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
// this would hinder the ability for the time_zone_detector to judge which suggestions are
|
||||
// based on newer information when comparing suggestions between different sources.
|
||||
long effectiveFromElapsedMillis = providerSuggestion.getElapsedRealtimeMillis();
|
||||
GeolocationTimeZoneSuggestion geoSuggestion =
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
effectiveFromElapsedMillis, providerSuggestion.getTimeZoneIds());
|
||||
|
||||
String debugInfo = "Event received provider=" + provider
|
||||
String debugInfo = "Provider event received: provider=" + provider
|
||||
+ ", providerEvent=" + providerEvent
|
||||
+ ", suggestionCreationTime=" + mEnvironment.elapsedRealtimeMillis();
|
||||
geoSuggestion.addDebugInfo(debugInfo);
|
||||
makeSuggestion(geoSuggestion, STATE_CERTAIN);
|
||||
reportSuggestionEvent(suggestion, debugInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -647,7 +676,7 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
+ mEnvironment.getProviderInitializationTimeoutFuzz());
|
||||
ipw.println("uncertaintyDelay=" + mEnvironment.getUncertaintyDelay());
|
||||
ipw.println("mState=" + mState.get());
|
||||
ipw.println("mLastSuggestion=" + mLastSuggestion);
|
||||
ipw.println("mLastEvent=" + mLastEvent);
|
||||
|
||||
ipw.println("State history:");
|
||||
ipw.increaseIndent(); // level 2
|
||||
@@ -668,19 +697,6 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an immediate suggestion and enters a new state if needed. This method updates
|
||||
* mLastSuggestion and changes mStateEnum / reports the new state for metrics.
|
||||
*/
|
||||
@GuardedBy("mSharedLock")
|
||||
private void makeSuggestion(@NonNull GeolocationTimeZoneSuggestion suggestion,
|
||||
@State String newState) {
|
||||
debugLog("makeSuggestion: suggestion=" + suggestion);
|
||||
mCallback.suggest(suggestion);
|
||||
mLastSuggestion = suggestion;
|
||||
setState(newState);
|
||||
}
|
||||
|
||||
/** Clears the uncertainty timeout. */
|
||||
@GuardedBy("mSharedLock")
|
||||
private void cancelUncertaintyTimeout() {
|
||||
@@ -688,18 +704,16 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a provider has become "uncertain" about the time zone.
|
||||
* Called when a provider has reported it is "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 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.
|
||||
* multiple ones available. The controller is therefore responsible for deciding when to pass
|
||||
* the "uncertain" suggestion to the downstream time zone detector.
|
||||
*
|
||||
* <p>This method schedules an "uncertainty" timeout (if one isn't already scheduled) to be
|
||||
* triggered later if nothing else preempts it. It can be preempted if the provider becomes
|
||||
* certain (or does anything else that calls {@link
|
||||
* #makeSuggestion(GeolocationTimeZoneSuggestion, String)}) within {@link
|
||||
* Environment#getUncertaintyDelay()}. Preemption causes the scheduled
|
||||
* certain within {@link Environment#getUncertaintyDelay()}. Preemption causes the scheduled
|
||||
* "uncertainty" timeout to be cancelled. If the provider repeatedly sends uncertainty events
|
||||
* within the uncertainty delay period, those events are effectively ignored (i.e. the timeout
|
||||
* is not reset each time).
|
||||
@@ -741,6 +755,8 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
synchronized (mSharedLock) {
|
||||
long afterUncertaintyTimeoutElapsedMillis = mEnvironment.elapsedRealtimeMillis();
|
||||
|
||||
setState(STATE_UNCERTAIN);
|
||||
|
||||
// For the effectiveFromElapsedMillis suggestion property, use the
|
||||
// uncertaintyStartedElapsedMillis. This is the time when the provider first reported
|
||||
// uncertainty, i.e. before the uncertainty timeout.
|
||||
@@ -749,30 +765,65 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
// the location_time_zone_manager finally confirms that the time zone was uncertain,
|
||||
// but the suggestion property allows the information to be back-dated, which should
|
||||
// help when comparing suggestions from different sources.
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
|
||||
uncertaintyStartedElapsedMillis,
|
||||
"Uncertainty timeout triggered for " + provider.getName() + ":"
|
||||
+ " primary=" + mPrimaryProvider
|
||||
+ ", secondary=" + mSecondaryProvider
|
||||
+ ", uncertaintyStarted="
|
||||
+ Duration.ofMillis(uncertaintyStartedElapsedMillis)
|
||||
+ ", afterUncertaintyTimeout="
|
||||
+ Duration.ofMillis(afterUncertaintyTimeoutElapsedMillis)
|
||||
+ ", uncertaintyDelay=" + uncertaintyDelay
|
||||
);
|
||||
makeSuggestion(suggestion, STATE_UNCERTAIN);
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(
|
||||
uncertaintyStartedElapsedMillis);
|
||||
String debugInfo = "Uncertainty timeout triggered for " + provider.getName() + ":"
|
||||
+ " primary=" + mPrimaryProvider
|
||||
+ ", secondary=" + mSecondaryProvider
|
||||
+ ", uncertaintyStarted="
|
||||
+ Duration.ofMillis(uncertaintyStartedElapsedMillis)
|
||||
+ ", afterUncertaintyTimeout="
|
||||
+ Duration.ofMillis(afterUncertaintyTimeoutElapsedMillis)
|
||||
+ ", uncertaintyDelay=" + uncertaintyDelay;
|
||||
reportSuggestionEvent(suggestion, debugInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mSharedLock")
|
||||
@NonNull
|
||||
private static GeolocationTimeZoneSuggestion createUncertainSuggestion(
|
||||
@ElapsedRealtimeLong long effectiveFromElapsedMillis,
|
||||
@NonNull String reason) {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(
|
||||
effectiveFromElapsedMillis);
|
||||
suggestion.addDebugInfo(reason);
|
||||
return suggestion;
|
||||
private LocationTimeZoneAlgorithmStatus generateCurrentAlgorithmStatus() {
|
||||
@State String controllerState = mState.get();
|
||||
ProviderState primaryProviderState = mPrimaryProvider.getCurrentState();
|
||||
ProviderState secondaryProviderState = mSecondaryProvider.getCurrentState();
|
||||
return createAlgorithmStatus(controllerState, primaryProviderState, secondaryProviderState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static LocationTimeZoneAlgorithmStatus createAlgorithmStatus(
|
||||
@NonNull @State String controllerState,
|
||||
@NonNull ProviderState primaryProviderState,
|
||||
@NonNull ProviderState secondaryProviderState) {
|
||||
|
||||
@DetectionAlgorithmStatus int algorithmStatus =
|
||||
mapControllerStateToDetectionAlgorithmStatus(controllerState);
|
||||
@ProviderStatus int primaryProviderStatus = primaryProviderState.getProviderStatus();
|
||||
@ProviderStatus int secondaryProviderStatus = secondaryProviderState.getProviderStatus();
|
||||
|
||||
// Neither provider is running. The algorithm is not running.
|
||||
return new LocationTimeZoneAlgorithmStatus(algorithmStatus,
|
||||
primaryProviderStatus, primaryProviderState.getReportedStatus(),
|
||||
secondaryProviderStatus, secondaryProviderState.getReportedStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the internal state enum value to one of the status values exposed to the layers above.
|
||||
*/
|
||||
private static @DetectionAlgorithmStatus int mapControllerStateToDetectionAlgorithmStatus(
|
||||
@NonNull @State String controllerState) {
|
||||
switch (controllerState) {
|
||||
case STATE_INITIALIZING:
|
||||
case STATE_PROVIDERS_INITIALIZING:
|
||||
case STATE_CERTAIN:
|
||||
case STATE_UNCERTAIN:
|
||||
return DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
case STATE_STOPPED:
|
||||
case STATE_DESTROYED:
|
||||
case STATE_FAILED:
|
||||
case STATE_UNKNOWN:
|
||||
default:
|
||||
return DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -798,8 +849,8 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
synchronized (mSharedLock) {
|
||||
LocationTimeZoneManagerServiceState.Builder builder =
|
||||
new LocationTimeZoneManagerServiceState.Builder();
|
||||
if (mLastSuggestion != null) {
|
||||
builder.setLastSuggestion(mLastSuggestion);
|
||||
if (mLastEvent != null) {
|
||||
builder.setLastEvent(mLastEvent);
|
||||
}
|
||||
builder.setControllerState(mState.get())
|
||||
.setStateChanges(mRecordedStates)
|
||||
@@ -867,17 +918,15 @@ class LocationTimeZoneProviderController implements Dumpable {
|
||||
abstract static class Callback {
|
||||
|
||||
@NonNull protected final ThreadingDomain mThreadingDomain;
|
||||
@NonNull protected final Object mSharedLock;
|
||||
|
||||
Callback(@NonNull ThreadingDomain threadingDomain) {
|
||||
mThreadingDomain = Objects.requireNonNull(threadingDomain);
|
||||
mSharedLock = threadingDomain.getLockObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests the latest time zone state for the device.
|
||||
*/
|
||||
abstract void suggest(@NonNull GeolocationTimeZoneSuggestion suggestion);
|
||||
abstract void sendEvent(@NonNull LocationAlgorithmEvent event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.android.server.timezonedetector.location;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
import com.android.server.timezonedetector.LocationAlgorithmEvent;
|
||||
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
|
||||
|
||||
/**
|
||||
@@ -34,11 +34,11 @@ class LocationTimeZoneProviderControllerCallbackImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
void suggest(@NonNull GeolocationTimeZoneSuggestion suggestion) {
|
||||
void sendEvent(@NonNull LocationAlgorithmEvent event) {
|
||||
mThreadingDomain.assertCurrentThread();
|
||||
|
||||
TimeZoneDetectorInternal timeZoneDetector =
|
||||
LocalServices.getService(TimeZoneDetectorInternal.class);
|
||||
timeZoneDetector.suggestGeolocationTimeZone(suggestion);
|
||||
timeZoneDetector.handleLocationAlgorithmEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,14 @@ import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneDetectorStatus;
|
||||
import android.app.time.TimeZoneState;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
|
||||
@@ -34,14 +36,17 @@ public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
new FakeServiceConfigAccessor();
|
||||
private final ArrayList<StateChangeListener> mListeners = new ArrayList<>();
|
||||
private TimeZoneState mTimeZoneState;
|
||||
private TimeZoneDetectorStatus mStatus;
|
||||
|
||||
public FakeTimeZoneDetectorStrategy() {
|
||||
mFakeServiceConfigAccessor.addConfigurationInternalChangeListener(
|
||||
this::notifyChangeListeners);
|
||||
}
|
||||
|
||||
public void initializeConfiguration(ConfigurationInternal configuration) {
|
||||
public void initializeConfigurationAndStatus(
|
||||
ConfigurationInternal configuration, TimeZoneDetectorStatus status) {
|
||||
mFakeServiceConfigAccessor.initializeCurrentUserConfiguration(configuration);
|
||||
mStatus = Objects.requireNonNull(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,6 +62,7 @@ public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
assertEquals("Multi-user testing not supported",
|
||||
configurationInternal.getUserId(), userId);
|
||||
return new TimeZoneCapabilitiesAndConfig(
|
||||
mStatus,
|
||||
configurationInternal.asCapabilities(bypassUserPolicyChecks),
|
||||
configurationInternal.asConfiguration());
|
||||
}
|
||||
@@ -90,7 +96,7 @@ public class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGeolocationTimeZone(GeolocationTimeZoneSuggestion timeZoneSuggestion) {
|
||||
public void handleLocationAlgorithmEvent(LocationAlgorithmEvent locationAlgorithmEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,13 +16,8 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static com.android.server.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -49,11 +44,6 @@ public class GeolocationTimeZoneSuggestionTest {
|
||||
assertEquals(certain1v1, certain1v2);
|
||||
assertEquals(certain1v2, certain1v1);
|
||||
|
||||
// DebugInfo must not be considered in equals().
|
||||
certain1v1.addDebugInfo("Debug info 1");
|
||||
certain1v2.addDebugInfo("Debug info 2");
|
||||
assertEquals(certain1v1, certain1v2);
|
||||
|
||||
long time2 = 2222L;
|
||||
GeolocationTimeZoneSuggestion certain2 =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(time2, ARBITRARY_ZONE_IDS1);
|
||||
@@ -71,40 +61,4 @@ public class GeolocationTimeZoneSuggestionTest {
|
||||
assertNotEquals(certain1v1, certain3);
|
||||
assertNotEquals(certain3, certain1v1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noZoneIdsArg() {
|
||||
ShellCommand testShellCommand =
|
||||
createShellCommandWithArgsAndOptions(Collections.emptyList());
|
||||
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_zoneIdsUncertain() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--zone_ids UNCERTAIN");
|
||||
assertNull(GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand)
|
||||
.getZoneIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_zoneIdsEmpty() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--zone_ids EMPTY");
|
||||
assertEquals(Collections.emptyList(),
|
||||
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand).getZoneIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_zoneIdsPresent() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
"--zone_ids Europe/London,Europe/Paris");
|
||||
assertEquals(Arrays.asList("Europe/London", "Europe/Paris"),
|
||||
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand).getZoneIds());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_unknownArgument() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--bad_arg 0");
|
||||
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_NOT_APPLICABLE;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
|
||||
|
||||
import static com.android.server.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.os.ShellCommand;
|
||||
import android.service.timezone.TimeZoneProviderStatus;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class LocationAlgorithmEventTest {
|
||||
|
||||
public static final TimeZoneProviderStatus ARBITRARY_PROVIDER_STATUS =
|
||||
new TimeZoneProviderStatus.Builder()
|
||||
.setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
|
||||
.setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
|
||||
.setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
|
||||
.build();
|
||||
|
||||
public static final LocationTimeZoneAlgorithmStatus ARBITRARY_LOCATION_ALGORITHM_STATUS =
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, ARBITRARY_PROVIDER_STATUS,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
GeolocationTimeZoneSuggestion suggestion1 =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(1111L);
|
||||
LocationTimeZoneAlgorithmStatus status1 = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null, PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
LocationAlgorithmEvent event1v1 = new LocationAlgorithmEvent(status1, suggestion1);
|
||||
assertEqualsAndHashCode(event1v1, event1v1);
|
||||
|
||||
LocationAlgorithmEvent event1v2 = new LocationAlgorithmEvent(status1, suggestion1);
|
||||
assertEqualsAndHashCode(event1v1, event1v2);
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion2 =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(2222L);
|
||||
LocationAlgorithmEvent event2 = new LocationAlgorithmEvent(status1, suggestion2);
|
||||
assertNotEquals(event1v1, event2);
|
||||
|
||||
LocationTimeZoneAlgorithmStatus status2 = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null, PROVIDER_STATUS_NOT_READY, null);
|
||||
LocationAlgorithmEvent event3 = new LocationAlgorithmEvent(status2, suggestion1);
|
||||
assertNotEquals(event1v1, event3);
|
||||
|
||||
// DebugInfo must not be considered in equals().
|
||||
event1v1.addDebugInfo("Debug info 1");
|
||||
event1v2.addDebugInfo("Debug info 2");
|
||||
assertEquals(event1v1, event1v2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noStatus() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(1111L);
|
||||
ShellCommand testShellCommand =
|
||||
createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--suggestion", suggestion.toString()));
|
||||
|
||||
LocationAlgorithmEvent.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_noSuggestion() {
|
||||
GeolocationTimeZoneSuggestion suggestion = null;
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS, suggestion);
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--status", event.getAlgorithmStatus().toString()));
|
||||
|
||||
assertEquals(event, LocationAlgorithmEvent.parseCommandLineArg(testShellCommand));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_suggestionUncertain() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createUncertainSuggestion(1111L);
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS, suggestion);
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--status", event.getAlgorithmStatus().toString(),
|
||||
"--suggestion", "UNCERTAIN"));
|
||||
|
||||
LocationAlgorithmEvent parsedEvent =
|
||||
LocationAlgorithmEvent.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(event.getAlgorithmStatus(), parsedEvent.getAlgorithmStatus());
|
||||
assertEquals(event.getSuggestion().getZoneIds(), parsedEvent.getSuggestion().getZoneIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_suggestionEmpty() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
1111L, Collections.emptyList());
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS, suggestion);
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--status", event.getAlgorithmStatus().toString(),
|
||||
"--suggestion", "EMPTY"));
|
||||
|
||||
LocationAlgorithmEvent parsedEvent =
|
||||
LocationAlgorithmEvent.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(event.getAlgorithmStatus(), parsedEvent.getAlgorithmStatus());
|
||||
assertEquals(event.getSuggestion().getZoneIds(), parsedEvent.getSuggestion().getZoneIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCommandLineArg_suggestionPresent() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
1111L, Arrays.asList("Europe/London", "Europe/Paris"));
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS, suggestion);
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--status", event.getAlgorithmStatus().toString(),
|
||||
"--suggestion", "Europe/London,Europe/Paris"));
|
||||
|
||||
LocationAlgorithmEvent parsedEvent =
|
||||
LocationAlgorithmEvent.parseCommandLineArg(testShellCommand);
|
||||
assertEquals(event.getAlgorithmStatus(), parsedEvent.getAlgorithmStatus());
|
||||
assertEquals(event.getSuggestion().getZoneIds(), parsedEvent.getSuggestion().getZoneIds());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_unknownArgument() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
1111L, Arrays.asList("Europe/London", "Europe/Paris"));
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_ALGORITHM_STATUS, suggestion);
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
Arrays.asList("--status", event.getAlgorithmStatus().toString(),
|
||||
"--suggestion", "Europe/London,Europe/Paris", "--bad_arg"));
|
||||
LocationAlgorithmEvent.parseCommandLineArg(testShellCommand);
|
||||
}
|
||||
|
||||
private static void assertEqualsAndHashCode(Object one, Object two) {
|
||||
assertEquals(one, two);
|
||||
assertEquals(two, one);
|
||||
assertEquals(one.hashCode(), two.hashCode());
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
|
||||
import static com.android.server.timezonedetector.MetricsTimeZoneDetectorState.DETECTION_MODE_GEO;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -23,6 +27,7 @@ import static org.junit.Assert.assertNull;
|
||||
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
|
||||
@@ -31,6 +36,7 @@ import com.android.server.timezonedetector.MetricsTimeZoneDetectorState.MetricsT
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Tests for {@link MetricsTimeZoneDetectorState}. */
|
||||
@@ -38,6 +44,9 @@ public class MetricsTimeZoneDetectorStateTest {
|
||||
|
||||
private static final @UserIdInt int ARBITRARY_USER_ID = 1;
|
||||
private static final @ElapsedRealtimeLong long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
|
||||
private static final LocationTimeZoneAlgorithmStatus ARBITRARY_CERTAIN_STATUS =
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, null, PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
private static final String DEVICE_TIME_ZONE_ID = "DeviceTimeZoneId";
|
||||
|
||||
private static final ManualTimeZoneSuggestion MANUAL_TIME_ZONE_SUGGESTION =
|
||||
@@ -50,11 +59,14 @@ public class MetricsTimeZoneDetectorStateTest {
|
||||
.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
|
||||
.build();
|
||||
|
||||
private static final GeolocationTimeZoneSuggestion GEOLOCATION_TIME_ZONE_SUGGESTION =
|
||||
public static final GeolocationTimeZoneSuggestion GEOLOCATION_SUGGESTION_CERTAIN =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
ARBITRARY_ELAPSED_REALTIME_MILLIS,
|
||||
Arrays.asList("GeoTimeZoneId1", "GeoTimeZoneId2"));
|
||||
|
||||
private static final LocationAlgorithmEvent LOCATION_ALGORITHM_EVENT =
|
||||
new LocationAlgorithmEvent(ARBITRARY_CERTAIN_STATUS, GEOLOCATION_SUGGESTION_CERTAIN);
|
||||
|
||||
private final OrdinalGenerator<String> mOrdinalGenerator =
|
||||
new OrdinalGenerator<>(Function.identity());
|
||||
|
||||
@@ -68,7 +80,7 @@ public class MetricsTimeZoneDetectorStateTest {
|
||||
MetricsTimeZoneDetectorState metricsTimeZoneDetectorState =
|
||||
MetricsTimeZoneDetectorState.create(mOrdinalGenerator, configurationInternal,
|
||||
DEVICE_TIME_ZONE_ID, MANUAL_TIME_ZONE_SUGGESTION,
|
||||
TELEPHONY_TIME_ZONE_SUGGESTION, GEOLOCATION_TIME_ZONE_SUGGESTION);
|
||||
TELEPHONY_TIME_ZONE_SUGGESTION, LOCATION_ALGORITHM_EVENT);
|
||||
|
||||
// Assert the content.
|
||||
assertCommonConfiguration(configurationInternal, metricsTimeZoneDetectorState);
|
||||
@@ -88,9 +100,10 @@ public class MetricsTimeZoneDetectorStateTest {
|
||||
assertEquals(expectedTelephonySuggestion,
|
||||
metricsTimeZoneDetectorState.getLatestTelephonySuggestion());
|
||||
|
||||
List<String> expectedZoneIds = LOCATION_ALGORITHM_EVENT.getSuggestion().getZoneIds();
|
||||
MetricsTimeZoneSuggestion expectedGeoSuggestion =
|
||||
MetricsTimeZoneSuggestion.createCertain(
|
||||
GEOLOCATION_TIME_ZONE_SUGGESTION.getZoneIds().toArray(new String[0]),
|
||||
expectedZoneIds.toArray(new String[0]),
|
||||
new int[] { 3, 4 });
|
||||
assertEquals(expectedGeoSuggestion,
|
||||
metricsTimeZoneDetectorState.getLatestGeolocationSuggestion());
|
||||
@@ -106,7 +119,7 @@ public class MetricsTimeZoneDetectorStateTest {
|
||||
MetricsTimeZoneDetectorState metricsTimeZoneDetectorState =
|
||||
MetricsTimeZoneDetectorState.create(mOrdinalGenerator, configurationInternal,
|
||||
DEVICE_TIME_ZONE_ID, MANUAL_TIME_ZONE_SUGGESTION,
|
||||
TELEPHONY_TIME_ZONE_SUGGESTION, GEOLOCATION_TIME_ZONE_SUGGESTION);
|
||||
TELEPHONY_TIME_ZONE_SUGGESTION, LOCATION_ALGORITHM_EVENT);
|
||||
|
||||
// Assert the content.
|
||||
assertCommonConfiguration(configurationInternal, metricsTimeZoneDetectorState);
|
||||
|
||||
@@ -16,14 +16,22 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TelephonyTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneDetectorStatus;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.content.Context;
|
||||
import android.os.HandlerThread;
|
||||
@@ -41,6 +49,15 @@ import java.util.List;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TimeZoneDetectorInternalImplTest {
|
||||
|
||||
private static final TelephonyTimeZoneAlgorithmStatus ARBITRARY_TELEPHONY_STATUS =
|
||||
new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
private static final LocationTimeZoneAlgorithmStatus ARBITRARY_LOCATION_CERTAIN_STATUS =
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, null, PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
private static final TimeZoneDetectorStatus ARBITRARY_DETECTOR_STATUS =
|
||||
new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING, ARBITRARY_TELEPHONY_STATUS,
|
||||
ARBITRARY_LOCATION_CERTAIN_STATUS);
|
||||
|
||||
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
|
||||
private static final String ARBITRARY_ZONE_ID = "TestZoneId";
|
||||
private static final List<String> ARBITRARY_ZONE_IDS = Arrays.asList(ARBITRARY_ZONE_ID);
|
||||
@@ -81,7 +98,8 @@ public class TimeZoneDetectorInternalImplTest {
|
||||
public void testGetCapabilitiesAndConfigForDpm() throws Exception {
|
||||
final boolean autoDetectionEnabled = true;
|
||||
ConfigurationInternal testConfig = createConfigurationInternal(autoDetectionEnabled);
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfiguration(testConfig);
|
||||
TimeZoneDetectorStatus testStatus = ARBITRARY_DETECTOR_STATUS;
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfigurationAndStatus(testConfig, testStatus);
|
||||
|
||||
TimeZoneCapabilitiesAndConfig actualCapabilitiesAndConfig =
|
||||
mTimeZoneDetectorInternal.getCapabilitiesAndConfigForDpm();
|
||||
@@ -93,6 +111,7 @@ public class TimeZoneDetectorInternalImplTest {
|
||||
|
||||
TimeZoneCapabilitiesAndConfig expectedCapabilitiesAndConfig =
|
||||
new TimeZoneCapabilitiesAndConfig(
|
||||
testStatus,
|
||||
testConfig.asCapabilities(expectedBypassUserPolicyChecks),
|
||||
testConfig.asConfiguration());
|
||||
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
|
||||
@@ -103,7 +122,9 @@ public class TimeZoneDetectorInternalImplTest {
|
||||
final boolean autoDetectionEnabled = false;
|
||||
ConfigurationInternal initialConfigurationInternal =
|
||||
createConfigurationInternal(autoDetectionEnabled);
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfiguration(initialConfigurationInternal);
|
||||
TimeZoneDetectorStatus testStatus = ARBITRARY_DETECTOR_STATUS;
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfigurationAndStatus(
|
||||
initialConfigurationInternal, testStatus);
|
||||
|
||||
TimeZoneConfiguration timeConfiguration = new TimeZoneConfiguration.Builder()
|
||||
.setAutoDetectionEnabled(true)
|
||||
@@ -131,13 +152,15 @@ public class TimeZoneDetectorInternalImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestGeolocationTimeZone() throws Exception {
|
||||
public void testHandleLocationAlgorithmEvent() throws Exception {
|
||||
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
|
||||
mTimeZoneDetectorInternal.suggestGeolocationTimeZone(timeZoneSuggestion);
|
||||
LocationAlgorithmEvent suggestionEvent = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_CERTAIN_STATUS, timeZoneSuggestion);
|
||||
mTimeZoneDetectorInternal.handleLocationAlgorithmEvent(suggestionEvent);
|
||||
mTestHandler.assertTotalMessagesEnqueued(1);
|
||||
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
verify(mFakeTimeZoneDetectorStrategySpy).suggestGeolocationTimeZone(timeZoneSuggestion);
|
||||
verify(mFakeTimeZoneDetectorStrategySpy).handleLocationAlgorithmEvent(suggestionEvent);
|
||||
}
|
||||
private static ManualTimeZoneSuggestion createManualTimeZoneSuggestion() {
|
||||
return new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID);
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
@@ -34,8 +39,11 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.time.ITimeZoneDetectorListener;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TelephonyTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneDetectorStatus;
|
||||
import android.app.time.TimeZoneState;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
@@ -59,6 +67,13 @@ import java.util.List;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TimeZoneDetectorServiceTest {
|
||||
|
||||
private static final LocationTimeZoneAlgorithmStatus ARBITRARY_LOCATION_CERTAIN_STATUS =
|
||||
new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_IS_CERTAIN, null, PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
private static final TimeZoneDetectorStatus ARBITRARY_DETECTOR_STATUS =
|
||||
new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING,
|
||||
new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING),
|
||||
ARBITRARY_LOCATION_CERTAIN_STATUS);
|
||||
private static final int ARBITRARY_USER_ID = 9999;
|
||||
private static final List<String> ARBITRARY_TIME_ZONE_IDS = Arrays.asList("TestZoneId");
|
||||
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
|
||||
@@ -113,7 +128,8 @@ public class TimeZoneDetectorServiceTest {
|
||||
|
||||
ConfigurationInternal configuration =
|
||||
createConfigurationInternal(true /* autoDetectionEnabled*/);
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfiguration(configuration);
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfigurationAndStatus(configuration,
|
||||
ARBITRARY_DETECTOR_STATUS);
|
||||
|
||||
TimeZoneCapabilitiesAndConfig actualCapabilitiesAndConfig =
|
||||
mTimeZoneDetectorService.getCapabilitiesAndConfig();
|
||||
@@ -128,6 +144,7 @@ public class TimeZoneDetectorServiceTest {
|
||||
|
||||
TimeZoneCapabilitiesAndConfig expectedCapabilitiesAndConfig =
|
||||
new TimeZoneCapabilitiesAndConfig(
|
||||
ARBITRARY_DETECTOR_STATUS,
|
||||
configuration.asCapabilities(expectedBypassUserPolicyChecks),
|
||||
configuration.asConfiguration());
|
||||
assertEquals(expectedCapabilitiesAndConfig, actualCapabilitiesAndConfig);
|
||||
@@ -161,7 +178,9 @@ public class TimeZoneDetectorServiceTest {
|
||||
public void testListenerRegistrationAndCallbacks() throws Exception {
|
||||
ConfigurationInternal initialConfiguration =
|
||||
createConfigurationInternal(false /* autoDetectionEnabled */);
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfiguration(initialConfiguration);
|
||||
|
||||
mFakeTimeZoneDetectorStrategySpy.initializeConfigurationAndStatus(
|
||||
initialConfiguration, ARBITRARY_DETECTOR_STATUS);
|
||||
|
||||
IBinder mockListenerBinder = mock(IBinder.class);
|
||||
ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
|
||||
@@ -231,31 +250,35 @@ public class TimeZoneDetectorServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestGeolocationTimeZone_withoutPermission() {
|
||||
public void testHandleLocationAlgorithmEvent_withoutPermission() {
|
||||
doThrow(new SecurityException("Mock"))
|
||||
.when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_CERTAIN_STATUS, timeZoneSuggestion);
|
||||
|
||||
assertThrows(SecurityException.class,
|
||||
() -> mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion));
|
||||
() -> mTimeZoneDetectorService.handleLocationAlgorithmEvent(event));
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.SET_TIME_ZONE), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestGeolocationTimeZone() throws Exception {
|
||||
public void testHandleLocationAlgorithmEvent() throws Exception {
|
||||
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(
|
||||
ARBITRARY_LOCATION_CERTAIN_STATUS, timeZoneSuggestion);
|
||||
|
||||
mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion);
|
||||
mTimeZoneDetectorService.handleLocationAlgorithmEvent(event);
|
||||
mTestHandler.assertTotalMessagesEnqueued(1);
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.SET_TIME_ZONE), anyString());
|
||||
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
verify(mFakeTimeZoneDetectorStrategySpy).suggestGeolocationTimeZone(timeZoneSuggestion);
|
||||
verify(mFakeTimeZoneDetectorStrategySpy).handleLocationAlgorithmEvent(event);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
|
||||
package com.android.server.timezonedetector;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_UNCERTAIN;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
|
||||
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
|
||||
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
|
||||
@@ -35,6 +41,7 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.T
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -47,8 +54,11 @@ import static org.mockito.Mockito.verify;
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.LocationTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TelephonyTimeZoneAlgorithmStatus;
|
||||
import android.app.time.TimeZoneCapabilitiesAndConfig;
|
||||
import android.app.time.TimeZoneConfiguration;
|
||||
import android.app.time.TimeZoneDetectorStatus;
|
||||
import android.app.time.TimeZoneState;
|
||||
import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
@@ -189,6 +199,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.setGeoDetectionEnabledSetting(true)
|
||||
.build();
|
||||
|
||||
private static final TelephonyTimeZoneAlgorithmStatus TELEPHONY_ALGORITHM_RUNNING_STATUS =
|
||||
new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
|
||||
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
|
||||
private FakeEnvironment mFakeEnvironment;
|
||||
private HandlerThread mHandlerThread;
|
||||
@@ -233,9 +246,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
{
|
||||
mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
|
||||
CONFIG_AUTO_DISABLED_GEO_DISABLED);
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
|
||||
stateChangeListener.assertNotificationsReceived(0);
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
assertEquals(CONFIG_AUTO_DISABLED_GEO_DISABLED,
|
||||
mTimeZoneDetectorStrategy.getCachedCapabilitiesAndConfigForTests());
|
||||
}
|
||||
@@ -244,10 +255,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
{
|
||||
mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
|
||||
CONFIG_AUTO_ENABLED_GEO_ENABLED);
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
|
||||
stateChangeListener.assertNotificationsReceived(1);
|
||||
stateChangeListener.resetNotificationsReceivedCount();
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
assertEquals(CONFIG_AUTO_ENABLED_GEO_ENABLED,
|
||||
mTimeZoneDetectorStrategy.getCachedCapabilitiesAndConfigForTests());
|
||||
}
|
||||
@@ -258,10 +266,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
new TimeZoneConfiguration.Builder().setGeoDetectionEnabled(false).build();
|
||||
mTimeZoneDetectorStrategy.updateConfiguration(
|
||||
USER_ID, requestedChanges, bypassUserPolicyChecks);
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
|
||||
stateChangeListener.assertNotificationsReceived(1);
|
||||
stateChangeListener.resetNotificationsReceivedCount();
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,11 +295,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
new TimeZoneConfiguration.Builder().setGeoDetectionEnabled(false).build();
|
||||
mTimeZoneDetectorStrategy.updateConfiguration(
|
||||
otherUserId, requestedChanges, bypassUserPolicyChecks);
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
|
||||
// Only changes to the current user's config are notified.
|
||||
stateChangeListener.assertNotificationsReceived(0);
|
||||
stateChangeListener.resetNotificationsReceivedCount();
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
}
|
||||
|
||||
// Current user behavior: the strategy caches and returns the latest configuration.
|
||||
@@ -426,9 +429,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedSlotIndex1ScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion,
|
||||
TELEPHONY_SCORE_NONE);
|
||||
assertEquals(expectedSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertNull(mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedSlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(SLOT_INDEX2, null);
|
||||
assertEquals(expectedSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
@@ -439,10 +442,10 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedSlotIndex2ScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(slotIndex2TimeZoneSuggestion,
|
||||
TELEPHONY_SCORE_NONE);
|
||||
assertEquals(expectedSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertEquals(expectedSlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedSlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX2, expectedSlotIndex2ScoredSuggestion);
|
||||
// SlotIndex1 should always beat slotIndex2, all other things being equal.
|
||||
assertEquals(expectedSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
@@ -477,8 +480,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(
|
||||
lowQualitySuggestion, testCase.expectedScore);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
}
|
||||
@@ -494,8 +497,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(
|
||||
goodQualitySuggestion, testCase2.expectedScore);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
}
|
||||
@@ -511,8 +514,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(
|
||||
lowQualitySuggestion2, testCase.expectedScore);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
}
|
||||
@@ -543,8 +546,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Assert internal service state.
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
|
||||
new QualifiedTelephonyTimeZoneSuggestion(suggestion, testCase.expectedScore);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
@@ -560,8 +563,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
@@ -570,8 +573,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedScoredSuggestion);
|
||||
assertEquals(expectedScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
}
|
||||
@@ -622,8 +625,8 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedZoneSlotIndex1ScoredSuggestion);
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
}
|
||||
@@ -677,10 +680,10 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertEquals(expectedEmptySlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedZoneSlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX2, expectedEmptySlotIndex2ScoredSuggestion);
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
@@ -690,10 +693,10 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
script.verifyTimeZoneNotChanged();
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedZoneSlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX2, expectedZoneSlotIndex2ScoredSuggestion);
|
||||
// SlotIndex1 should always beat slotIndex2, all other things being equal.
|
||||
assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
@@ -709,20 +712,20 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(expectedEmptySlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedEmptySlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX2, expectedZoneSlotIndex2ScoredSuggestion);
|
||||
assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
|
||||
|
||||
// Reset the state for the next loop.
|
||||
script.simulateTelephonyTimeZoneSuggestion(emptySlotIndex2Suggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
assertEquals(expectedEmptySlotIndex1ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
|
||||
assertEquals(expectedEmptySlotIndex2ScoredSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
|
||||
script.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX1, expectedEmptySlotIndex1ScoredSuggestion)
|
||||
.verifyLatestQualifiedTelephonySuggestionReceived(
|
||||
SLOT_INDEX2, expectedEmptySlotIndex2ScoredSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,53 +869,185 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoSuggestion_uncertain() {
|
||||
public void testLocationAlgorithmEvent_statusChangesOnly() {
|
||||
TestStateChangeListener stateChangeListener = new TestStateChangeListener();
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
|
||||
.resetConfigurationTracking();
|
||||
.resetConfigurationTracking()
|
||||
.registerStateChangeListener(stateChangeListener);
|
||||
|
||||
GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeolocationSuggestion();
|
||||
TimeZoneDetectorStatus expectedInitialDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
LocationTimeZoneAlgorithmStatus.UNKNOWN);
|
||||
script.verifyCachedDetectorStatus(expectedInitialDetectorStatus);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(uncertainSuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus1 = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING, PROVIDER_STATUS_NOT_READY, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus2 = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING, PROVIDER_STATUS_NOT_PRESENT, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
assertNotEquals(algorithmStatus1, algorithmStatus2);
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(uncertainSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
{
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
new LocationAlgorithmEvent(algorithmStatus1, null);
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Assert internal service state.
|
||||
TimeZoneDetectorStatus expectedDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
algorithmStatus1);
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
// Repeat the event to demonstrate the state change notifier is not triggered.
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Assert internal service state.
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
}
|
||||
|
||||
{
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
new LocationAlgorithmEvent(algorithmStatus2, null);
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Assert internal service state.
|
||||
TimeZoneDetectorStatus expectedDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
algorithmStatus2);
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
// Repeat the event to demonstrate the state change notifier is not triggered.
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Assert internal service state.
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoSuggestion_noZones() {
|
||||
public void testLocationAlgorithmEvent_uncertain() {
|
||||
TestStateChangeListener stateChangeListener = new TestStateChangeListener();
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
|
||||
.resetConfigurationTracking();
|
||||
.resetConfigurationTracking()
|
||||
.registerStateChangeListener(stateChangeListener);
|
||||
|
||||
GeolocationTimeZoneSuggestion noZonesSuggestion = createCertainGeolocationSuggestion();
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(noZonesSuggestion)
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(noZonesSuggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
TimeZoneDetectorStatus expectedDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
locationAlgorithmEvent.getAlgorithmStatus());
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
// Repeat the event to demonstrate the state change notifier is not triggered.
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
// Detector remains running and location algorithm is still uncertain so nothing to report.
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Assert internal service state.
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoSuggestion_oneZone() {
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
createCertainGeolocationSuggestion("Europe/London");
|
||||
|
||||
public void testLocationAlgorithmEvent_noZones() {
|
||||
TestStateChangeListener stateChangeListener = new TestStateChangeListener();
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
|
||||
.resetConfigurationTracking();
|
||||
.resetConfigurationTracking()
|
||||
.registerStateChangeListener(stateChangeListener);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(suggestion)
|
||||
.verifyTimeZoneChangedAndReset(suggestion);
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createCertainLocationAlgorithmEvent();
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
TimeZoneDetectorStatus expectedDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
locationAlgorithmEvent.getAlgorithmStatus());
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
// Repeat the event to demonstrate the state change notifier is not triggered.
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Assert internal service state.
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocationAlgorithmEvent_oneZone() {
|
||||
TestStateChangeListener stateChangeListener = new TestStateChangeListener();
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
|
||||
.resetConfigurationTracking()
|
||||
.registerStateChangeListener(stateChangeListener);
|
||||
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/London");
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneChangedAndReset(locationAlgorithmEvent);
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Assert internal service state.
|
||||
TimeZoneDetectorStatus expectedDetectorStatus = new TimeZoneDetectorStatus(
|
||||
DETECTOR_STATUS_RUNNING,
|
||||
TELEPHONY_ALGORITHM_RUNNING_STATUS,
|
||||
locationAlgorithmEvent.getAlgorithmStatus());
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
// Repeat the event to demonstrate the state change notifier is not triggered.
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Assert internal service state.
|
||||
script.verifyCachedDetectorStatus(expectedDetectorStatus)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,41 +1056,35 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
* set to until that unambiguously can't be correct.
|
||||
*/
|
||||
@Test
|
||||
public void testGeoSuggestion_multiZone() {
|
||||
GeolocationTimeZoneSuggestion londonOnlySuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/London");
|
||||
GeolocationTimeZoneSuggestion londonOrParisSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/Paris", "Europe/London");
|
||||
GeolocationTimeZoneSuggestion parisOnlySuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/Paris");
|
||||
|
||||
public void testLocationAlgorithmEvent_multiZone() {
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
|
||||
.resetConfigurationTracking();
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
|
||||
.verifyTimeZoneChangedAndReset(londonOnlySuggestion);
|
||||
assertEquals(londonOnlySuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
LocationAlgorithmEvent londonOnlyEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/London");
|
||||
script.simulateLocationAlgorithmEvent(londonOnlyEvent)
|
||||
.verifyTimeZoneChangedAndReset(londonOnlyEvent)
|
||||
.verifyLatestLocationAlgorithmEventReceived(londonOnlyEvent);
|
||||
|
||||
// Confirm bias towards the current device zone when there's multiple zones to choose from.
|
||||
script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
assertEquals(londonOrParisSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
LocationAlgorithmEvent londonOrParisEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/Paris", "Europe/London");
|
||||
script.simulateLocationAlgorithmEvent(londonOrParisEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyLatestLocationAlgorithmEventReceived(londonOrParisEvent);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(parisOnlySuggestion)
|
||||
.verifyTimeZoneChangedAndReset(parisOnlySuggestion);
|
||||
assertEquals(parisOnlySuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
LocationAlgorithmEvent parisOnlyEvent = createCertainLocationAlgorithmEvent("Europe/Paris");
|
||||
script.simulateLocationAlgorithmEvent(parisOnlyEvent)
|
||||
.verifyTimeZoneChangedAndReset(parisOnlyEvent)
|
||||
.verifyLatestLocationAlgorithmEventReceived(parisOnlyEvent);
|
||||
|
||||
// Now the suggestion that previously left the device on Europe/London will leave the device
|
||||
// on Europe/Paris.
|
||||
script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
assertEquals(londonOrParisSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
script.simulateLocationAlgorithmEvent(londonOrParisEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyLatestLocationAlgorithmEventReceived(londonOrParisEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -964,8 +1093,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
*/
|
||||
@Test
|
||||
public void testChangingGeoDetectionEnabled() {
|
||||
GeolocationTimeZoneSuggestion geolocationSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/London");
|
||||
TestStateChangeListener stateChangeListener = new TestStateChangeListener();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/London");
|
||||
TelephonyTimeZoneSuggestion telephonySuggestion = createTelephonySuggestion(
|
||||
SLOT_INDEX1, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
|
||||
"Europe/Paris");
|
||||
@@ -973,20 +1103,22 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
Script script = new Script()
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
|
||||
.simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
|
||||
.resetConfigurationTracking();
|
||||
.resetConfigurationTracking()
|
||||
.registerStateChangeListener(stateChangeListener);
|
||||
|
||||
// Add suggestions. Nothing should happen as time zone detection is disabled.
|
||||
script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
assertEquals(geolocationSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
// A detector status change is considered a "state change".
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
|
||||
.verifyTimeZoneNotChanged();
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyLatestTelephonySuggestionReceived(SLOT_INDEX1, telephonySuggestion);
|
||||
|
||||
assertEquals(telephonySuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion);
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 0);
|
||||
|
||||
// Toggling the time zone detection enabled setting on should cause the device setting to be
|
||||
// set from the telephony signal, as we've started with geolocation time zone detection
|
||||
@@ -994,18 +1126,25 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
script.simulateSetAutoMode(true)
|
||||
.verifyTimeZoneChangedAndReset(telephonySuggestion);
|
||||
|
||||
// A configuration change is considered a "state change".
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Changing the detection to enable geo detection will cause the device tz setting to
|
||||
// change to use the latest geolocation suggestion.
|
||||
script.simulateSetGeoDetectionEnabled(true)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion);
|
||||
.verifyTimeZoneChangedAndReset(locationAlgorithmEvent);
|
||||
|
||||
// A configuration change is considered a "state change".
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
|
||||
// Changing the detection to disable geo detection should cause the device tz setting to
|
||||
// change to the telephony suggestion.
|
||||
script.simulateSetGeoDetectionEnabled(false)
|
||||
.verifyTimeZoneChangedAndReset(telephonySuggestion);
|
||||
.verifyTimeZoneChangedAndReset(telephonySuggestion)
|
||||
.verifyLatestLocationAlgorithmEventReceived(locationAlgorithmEvent);
|
||||
|
||||
assertEquals(geolocationSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
// A configuration change is considered a "state change".
|
||||
assertStateChangeNotificationsSent(stateChangeListener, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1039,21 +1178,20 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
// Receiving an "uncertain" geolocation suggestion should have no effect.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(true);
|
||||
}
|
||||
|
||||
// Receiving a "certain" geolocation suggestion should disable telephony fallback mode.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion geolocationSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/London");
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/London");
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
}
|
||||
|
||||
@@ -1076,22 +1214,22 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Geolocation suggestions should continue to be used as normal (previous telephony
|
||||
// suggestions are not used, even when the geolocation suggestion is uncertain).
|
||||
{
|
||||
GeolocationTimeZoneSuggestion geolocationSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/Rome");
|
||||
LocationAlgorithmEvent certainLocationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/Rome");
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent)
|
||||
.verifyTimeZoneChangedAndReset(certainLocationAlgorithmEvent)
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent uncertainLocationAlgorithmEvent =
|
||||
createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(uncertainLocationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent)
|
||||
// No change needed, device will already be set to Europe/Rome.
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
@@ -1108,21 +1246,20 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
// Make the geolocation algorithm uncertain.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneChangedAndReset(lastTelephonySuggestion)
|
||||
.verifyTelephonyFallbackIsEnabled(true);
|
||||
}
|
||||
|
||||
// Make the geolocation algorithm certain, disabling telephony fallback.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion geolocationSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/Lisbon");
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/Lisbon");
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
|
||||
}
|
||||
@@ -1130,10 +1267,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Demonstrate what happens when geolocation is uncertain when telephony fallback is
|
||||
// enabled.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(false)
|
||||
.simulateEnableTelephonyFallback()
|
||||
@@ -1161,10 +1297,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
// Receiving an "uncertain" geolocation suggestion should have no effect.
|
||||
{
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(true);
|
||||
}
|
||||
@@ -1172,10 +1307,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Make an uncertain geolocation suggestion, there is no telephony suggestion to fall back
|
||||
// to
|
||||
{
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(true);
|
||||
}
|
||||
@@ -1185,17 +1319,16 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
// Geolocation suggestions should continue to be used as normal (previous telephony
|
||||
// suggestions are not used, even when the geolocation suggestion is uncertain).
|
||||
{
|
||||
GeolocationTimeZoneSuggestion geolocationSuggestion =
|
||||
createCertainGeolocationSuggestion("Europe/Rome");
|
||||
LocationAlgorithmEvent certainEvent =
|
||||
createCertainLocationAlgorithmEvent("Europe/Rome");
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(certainEvent)
|
||||
.verifyTimeZoneChangedAndReset(certainEvent)
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
|
||||
GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
|
||||
createUncertainGeolocationSuggestion();
|
||||
LocationAlgorithmEvent uncertainEvent = createUncertainLocationAlgorithmEvent();
|
||||
script.simulateIncrementClock()
|
||||
.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
|
||||
.simulateLocationAlgorithmEvent(uncertainEvent)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.verifyTelephonyFallbackIsEnabled(false);
|
||||
|
||||
@@ -1319,15 +1452,15 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
TelephonyTimeZoneSuggestion telephonySuggestion =
|
||||
createTelephonySuggestion(0 /* slotIndex */, MATCH_TYPE_NETWORK_COUNTRY_ONLY,
|
||||
QUALITY_SINGLE_ZONE, "Zone2");
|
||||
GeolocationTimeZoneSuggestion geolocationTimeZoneSuggestion =
|
||||
createCertainGeolocationSuggestion("Zone3", "Zone2");
|
||||
LocationAlgorithmEvent locationAlgorithmEvent =
|
||||
createCertainLocationAlgorithmEvent("Zone3", "Zone2");
|
||||
script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationTimeZoneSuggestion)
|
||||
.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
|
||||
.verifyTimeZoneNotChanged();
|
||||
|
||||
assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
|
||||
manualSuggestion, telephonySuggestion, geolocationTimeZoneSuggestion,
|
||||
manualSuggestion, telephonySuggestion, locationAlgorithmEvent,
|
||||
MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
|
||||
|
||||
// Update the config and confirm that the config metrics state updates also.
|
||||
@@ -1336,11 +1469,11 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.setGeoDetectionEnabledSetting(true)
|
||||
.build();
|
||||
|
||||
expectedDeviceTimeZoneId = geolocationTimeZoneSuggestion.getZoneIds().get(0);
|
||||
expectedDeviceTimeZoneId = locationAlgorithmEvent.getSuggestion().getZoneIds().get(0);
|
||||
script.simulateConfigurationInternalChange(expectedInternalConfig)
|
||||
.verifyTimeZoneChangedAndReset(expectedDeviceTimeZoneId, TIME_ZONE_CONFIDENCE_HIGH);
|
||||
assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
|
||||
manualSuggestion, telephonySuggestion, geolocationTimeZoneSuggestion,
|
||||
manualSuggestion, telephonySuggestion, locationAlgorithmEvent,
|
||||
MetricsTimeZoneDetectorState.DETECTION_MODE_GEO);
|
||||
}
|
||||
|
||||
@@ -1352,7 +1485,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
ConfigurationInternal expectedInternalConfig,
|
||||
String expectedDeviceTimeZoneId, ManualTimeZoneSuggestion expectedManualSuggestion,
|
||||
TelephonyTimeZoneSuggestion expectedTelephonySuggestion,
|
||||
GeolocationTimeZoneSuggestion expectedGeolocationTimeZoneSuggestion,
|
||||
LocationAlgorithmEvent expectedLocationAlgorithmEvent,
|
||||
int expectedDetectionMode) {
|
||||
|
||||
MetricsTimeZoneDetectorState actualState = mTimeZoneDetectorStrategy.generateMetricsState();
|
||||
@@ -1365,7 +1498,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
MetricsTimeZoneDetectorState.create(
|
||||
tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
|
||||
expectedManualSuggestion, expectedTelephonySuggestion,
|
||||
expectedGeolocationTimeZoneSuggestion);
|
||||
expectedLocationAlgorithmEvent);
|
||||
// Rely on MetricsTimeZoneDetectorState.equals() for time zone ID / ID ordinal comparisons.
|
||||
assertEquals(expectedState, actualState);
|
||||
}
|
||||
@@ -1405,20 +1538,37 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX2).build();
|
||||
}
|
||||
|
||||
private LocationAlgorithmEvent createCertainLocationAlgorithmEvent(@NonNull String... zoneIds) {
|
||||
GeolocationTimeZoneSuggestion suggestion = createCertainGeolocationSuggestion(zoneIds);
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING, PROVIDER_STATUS_IS_CERTAIN, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(algorithmStatus, suggestion);
|
||||
event.addDebugInfo("Test certain event");
|
||||
return event;
|
||||
}
|
||||
|
||||
private LocationAlgorithmEvent createUncertainLocationAlgorithmEvent() {
|
||||
GeolocationTimeZoneSuggestion suggestion = createUncertainGeolocationSuggestion();
|
||||
LocationTimeZoneAlgorithmStatus algorithmStatus = new LocationTimeZoneAlgorithmStatus(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING, PROVIDER_STATUS_IS_UNCERTAIN, null,
|
||||
PROVIDER_STATUS_NOT_PRESENT, null);
|
||||
LocationAlgorithmEvent event = new LocationAlgorithmEvent(algorithmStatus, suggestion);
|
||||
event.addDebugInfo("Test uncertain event");
|
||||
return event;
|
||||
}
|
||||
|
||||
private GeolocationTimeZoneSuggestion createUncertainGeolocationSuggestion() {
|
||||
return GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
mFakeEnvironment.elapsedRealtimeMillis(), null);
|
||||
return GeolocationTimeZoneSuggestion.createUncertainSuggestion(
|
||||
mFakeEnvironment.elapsedRealtimeMillis());
|
||||
}
|
||||
|
||||
private GeolocationTimeZoneSuggestion createCertainGeolocationSuggestion(
|
||||
@NonNull String... zoneIds) {
|
||||
assertNotNull(zoneIds);
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion =
|
||||
GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
mFakeEnvironment.elapsedRealtimeMillis(), Arrays.asList(zoneIds));
|
||||
suggestion.addDebugInfo("Test suggestion");
|
||||
return suggestion;
|
||||
return GeolocationTimeZoneSuggestion.createCertainSuggestion(
|
||||
mFakeEnvironment.elapsedRealtimeMillis(), Arrays.asList(zoneIds));
|
||||
}
|
||||
|
||||
static class FakeEnvironment implements TimeZoneDetectorStrategyImpl.Environment {
|
||||
@@ -1499,6 +1649,14 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void assertStateChangeNotificationsSent(
|
||||
TestStateChangeListener stateChangeListener, int expectedCount) {
|
||||
// State change notifications are asynchronous, so we have to wait.
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
|
||||
stateChangeListener.assertNotificationsReceivedAndReset(expectedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* A "fluent" class allows reuse of code in tests: initialization, simulation and verification
|
||||
* logic.
|
||||
@@ -1516,6 +1674,11 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script registerStateChangeListener(StateChangeListener stateChangeListener) {
|
||||
mTimeZoneDetectorStrategy.addChangeListener(stateChangeListener);
|
||||
return this;
|
||||
}
|
||||
|
||||
Script simulateIncrementClock() {
|
||||
mFakeEnvironment.incrementClock();
|
||||
return this;
|
||||
@@ -1555,11 +1718,10 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates the time zone detection strategy receiving a geolocation-originated
|
||||
* suggestion.
|
||||
* Simulates the time zone detection strategy receiving a location algorithm event.
|
||||
*/
|
||||
Script simulateGeolocationTimeZoneSuggestion(GeolocationTimeZoneSuggestion suggestion) {
|
||||
mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(suggestion);
|
||||
Script simulateLocationAlgorithmEvent(LocationAlgorithmEvent event) {
|
||||
mTimeZoneDetectorStrategy.handleLocationAlgorithmEvent(event);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1616,7 +1778,9 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyTimeZoneChangedAndReset(GeolocationTimeZoneSuggestion suggestion) {
|
||||
Script verifyTimeZoneChangedAndReset(LocationAlgorithmEvent event) {
|
||||
GeolocationTimeZoneSuggestion suggestion = event.getSuggestion();
|
||||
assertNotNull("Only events with suggestions can change the time zone", suggestion);
|
||||
assertEquals("Only use this method with unambiguous geo suggestions",
|
||||
1, suggestion.getZoneIds().size());
|
||||
verifyTimeZoneChangedAndReset(
|
||||
@@ -1631,6 +1795,32 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyCachedDetectorStatus(TimeZoneDetectorStatus expectedStatus) {
|
||||
assertEquals(expectedStatus,
|
||||
mTimeZoneDetectorStrategy.getCachedDetectorStatusForTests());
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyLatestLocationAlgorithmEventReceived(LocationAlgorithmEvent expectedEvent) {
|
||||
assertEquals(expectedEvent,
|
||||
mTimeZoneDetectorStrategy.getLatestLocationAlgorithmEvent());
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyLatestTelephonySuggestionReceived(int slotIndex,
|
||||
TelephonyTimeZoneSuggestion expectedSuggestion) {
|
||||
assertEquals(expectedSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(slotIndex).suggestion);
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyLatestQualifiedTelephonySuggestionReceived(int slotIndex,
|
||||
QualifiedTelephonyTimeZoneSuggestion expectedQualifiedSuggestion) {
|
||||
assertEquals(expectedQualifiedSuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
|
||||
return this;
|
||||
}
|
||||
|
||||
Script resetConfigurationTracking() {
|
||||
mFakeEnvironment.commitAllChanges();
|
||||
return this;
|
||||
@@ -1671,11 +1861,16 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
mNotificationsReceived++;
|
||||
}
|
||||
|
||||
public void resetNotificationsReceivedCount() {
|
||||
public void assertNotificationsReceivedAndReset(int expectedCount) {
|
||||
assertNotificationsReceived(expectedCount);
|
||||
resetNotificationsReceivedCount();
|
||||
}
|
||||
|
||||
private void resetNotificationsReceivedCount() {
|
||||
mNotificationsReceived = 0;
|
||||
}
|
||||
|
||||
public void assertNotificationsReceived(int expectedCount) {
|
||||
private void assertNotificationsReceived(int expectedCount) {
|
||||
assertEquals(expectedCount, mNotificationsReceived);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.server.timezonedetector.location;
|
||||
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
|
||||
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_NOT_APPLICABLE;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
|
||||
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE;
|
||||
@@ -42,6 +44,7 @@ import static com.android.server.timezonedetector.location.TestSupport.USER2_CON
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
@@ -51,6 +54,7 @@ import static java.util.Arrays.asList;
|
||||
import android.annotation.ElapsedRealtimeLong;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.time.DetectorStatusTypes.DetectionAlgorithmStatus;
|
||||
import android.os.SystemClock;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.service.timezone.TimeZoneProviderEvent;
|
||||
@@ -60,6 +64,7 @@ import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.server.timezonedetector.ConfigurationInternal;
|
||||
import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
|
||||
import com.android.server.timezonedetector.LocationAlgorithmEvent;
|
||||
import com.android.server.timezonedetector.TestState;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
|
||||
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
|
||||
@@ -141,7 +146,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.setFailDuringInitialization(true);
|
||||
|
||||
// Initialize. After initialization the providers must be initialized and one should be
|
||||
// started.
|
||||
// started. They should report their status change via the callback.
|
||||
controller.initialize(testEnvironment, mTestCallback);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
|
||||
@@ -154,7 +159,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -184,7 +190,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -211,7 +218,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING, STATE_FAILED);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -239,7 +247,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -262,7 +271,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -282,7 +292,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate time passing with no provider event being received from the primary.
|
||||
@@ -296,7 +307,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate time passing with no provider event being received from either the primary or
|
||||
@@ -311,7 +322,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Finally, the uncertainty timeout should cause the controller to make an uncertain
|
||||
@@ -324,7 +335,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestCallback.assertEventWithUncertainSuggestionReportedAndCommit();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -345,7 +356,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
@@ -358,7 +370,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -380,7 +392,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate time passing with no provider event being received from the primary.
|
||||
@@ -392,7 +405,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
@@ -405,7 +418,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -427,7 +440,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate time passing with no provider event being received from the primary.
|
||||
@@ -439,7 +453,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
@@ -453,7 +467,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -475,7 +489,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
@@ -488,7 +503,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -501,7 +516,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// And a third, different event should cause another suggestion.
|
||||
@@ -513,7 +528,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -535,7 +550,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate time passing with no provider event being received from the primary.
|
||||
@@ -547,7 +563,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
@@ -561,7 +577,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -575,7 +591,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// And a third, different event should cause another suggestion.
|
||||
@@ -588,7 +604,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -610,7 +626,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
@@ -623,7 +640,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -639,7 +656,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate a location event being received from the secondary provider. This should cause a
|
||||
@@ -654,7 +671,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -670,7 +687,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate time passing. This means the uncertainty timeout should fire and the uncertain
|
||||
@@ -683,7 +700,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN);
|
||||
mTestCallback.assertUncertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithUncertainSuggestionReportedAndCommit(
|
||||
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -705,7 +722,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a location event being received from the primary provider. This should cause a
|
||||
@@ -718,7 +736,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -733,7 +751,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// And a success event from the primary provider should cause the controller to make another
|
||||
@@ -747,7 +765,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
@@ -767,7 +785,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is enabled.
|
||||
@@ -778,7 +797,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
@@ -788,7 +808,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -807,7 +828,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is enabled.
|
||||
@@ -818,7 +840,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a success event being received from the primary provider.
|
||||
@@ -830,7 +853,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -843,8 +866,9 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
assertControllerState(controller, STATE_STOPPED);
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN, STATE_STOPPED);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -865,7 +889,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate the primary provider suggesting a time zone.
|
||||
@@ -879,7 +904,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -897,9 +922,9 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_UNCERTAIN, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -920,7 +945,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure location event being received from the primary provider. This should
|
||||
@@ -933,7 +959,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate uncertainty from the secondary.
|
||||
@@ -945,7 +971,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// And a success event from the secondary provider should cause the controller to make
|
||||
@@ -958,7 +984,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -971,7 +997,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
}
|
||||
|
||||
@@ -992,7 +1018,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure location event being received from the primary provider. This should
|
||||
@@ -1005,7 +1032,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
@@ -1015,7 +1042,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is enabled.
|
||||
@@ -1026,7 +1054,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -1047,7 +1076,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event from the primary. This will start the secondary, which will
|
||||
@@ -1062,7 +1092,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate failure event from the secondary. This should just affect the secondary's state.
|
||||
@@ -1074,7 +1104,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// And a success event from the primary provider should cause the controller to make
|
||||
@@ -1087,7 +1117,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -1100,7 +1130,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
}
|
||||
|
||||
@@ -1121,7 +1151,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate an uncertain event from the primary. This will start the secondary, which will
|
||||
@@ -1136,7 +1167,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Simulate failure event from the secondary. This should just affect the secondary's state.
|
||||
@@ -1148,7 +1179,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertUncertaintyTimeoutSet(testEnvironment, controller);
|
||||
|
||||
// Now signal a config change so that geo detection is disabled.
|
||||
@@ -1158,7 +1189,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Now signal a config change so that geo detection is enabled. Only the primary can be
|
||||
@@ -1170,7 +1202,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -1191,7 +1224,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate a failure event from the primary. This will start the secondary.
|
||||
@@ -1203,7 +1237,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
|
||||
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit();
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertNoEventReported();
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate failure event from the secondary.
|
||||
@@ -1214,7 +1248,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_FAILED);
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
}
|
||||
|
||||
@@ -1233,7 +1268,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
{
|
||||
LocationTimeZoneManagerServiceState state = controller.getStateForTests();
|
||||
assertEquals(STATE_INITIALIZING, state.getControllerState());
|
||||
assertNull(state.getLastSuggestion());
|
||||
assertNull(state.getLastEvent().getSuggestion());
|
||||
assertControllerRecordedStates(state,
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
assertProviderStates(state.getPrimaryProviderStates(),
|
||||
@@ -1251,7 +1286,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
{
|
||||
LocationTimeZoneManagerServiceState state = controller.getStateForTests();
|
||||
assertEquals(STATE_INITIALIZING, state.getControllerState());
|
||||
assertNull(state.getLastSuggestion());
|
||||
assertNull(state.getLastEvent().getSuggestion());
|
||||
assertControllerRecordedStates(state);
|
||||
assertProviderStates(
|
||||
state.getPrimaryProviderStates(), PROVIDER_STATE_STARTED_UNCERTAIN);
|
||||
@@ -1268,7 +1303,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
LocationTimeZoneManagerServiceState state = controller.getStateForTests();
|
||||
assertEquals(STATE_CERTAIN, state.getControllerState());
|
||||
assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
|
||||
state.getLastSuggestion().getZoneIds());
|
||||
state.getLastEvent().getSuggestion().getZoneIds());
|
||||
assertControllerRecordedStates(state, STATE_CERTAIN);
|
||||
assertProviderStates(state.getPrimaryProviderStates());
|
||||
assertProviderStates(
|
||||
@@ -1280,7 +1315,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
LocationTimeZoneManagerServiceState state = controller.getStateForTests();
|
||||
assertEquals(STATE_CERTAIN, state.getControllerState());
|
||||
assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
|
||||
state.getLastSuggestion().getZoneIds());
|
||||
state.getLastEvent().getSuggestion().getZoneIds());
|
||||
assertControllerRecordedStates(state);
|
||||
assertProviderStates(state.getPrimaryProviderStates());
|
||||
assertProviderStates(state.getSecondaryProviderStates());
|
||||
@@ -1313,7 +1348,8 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
|
||||
mTestCallback.assertNoSuggestionMade();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
// Simulate the primary provider suggesting a time zone.
|
||||
@@ -1327,7 +1363,7 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
|
||||
mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
|
||||
mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
|
||||
mTestCallback.assertEventWithCertainSuggestionReportedAndCommit(
|
||||
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
|
||||
assertFalse(controller.isUncertaintyTimeoutSet());
|
||||
|
||||
@@ -1335,11 +1371,11 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
controller.destroy();
|
||||
|
||||
assertControllerState(controller, STATE_DESTROYED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(
|
||||
STATE_UNCERTAIN, STATE_STOPPED, STATE_DESTROYED);
|
||||
mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED, STATE_DESTROYED);
|
||||
|
||||
// Confirm that the previous suggestion was overridden.
|
||||
mTestCallback.assertUncertainSuggestionMadeAndCommit();
|
||||
mTestCallback.assertEventWithNoSuggestionReportedAndCommit(
|
||||
DETECTION_ALGORITHM_STATUS_NOT_RUNNING);
|
||||
|
||||
mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(
|
||||
PROVIDER_STATE_STOPPED, PROVIDER_STATE_DESTROYED);
|
||||
@@ -1517,63 +1553,101 @@ public class LocationTimeZoneProviderControllerTest {
|
||||
|
||||
private static class TestCallback extends LocationTimeZoneProviderController.Callback {
|
||||
|
||||
private TestState<GeolocationTimeZoneSuggestion> mLatestSuggestion = new TestState<>();
|
||||
private TestState<LocationAlgorithmEvent> mLatestEvent = new TestState<>();
|
||||
|
||||
TestCallback(ThreadingDomain threadingDomain) {
|
||||
super(threadingDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
void suggest(GeolocationTimeZoneSuggestion suggestion) {
|
||||
mLatestSuggestion.set(suggestion);
|
||||
void sendEvent(LocationAlgorithmEvent event) {
|
||||
mLatestEvent.set(event);
|
||||
}
|
||||
|
||||
void assertCertainSuggestionMadeFromEventAndCommit(TimeZoneProviderEvent event) {
|
||||
void assertNoEventReported() {
|
||||
mLatestEvent.assertHasNotBeenSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts one or more events have been reported, and the most recent does not contain a
|
||||
* suggestion.
|
||||
*/
|
||||
void assertEventWithNoSuggestionReportedAndCommit(
|
||||
@DetectionAlgorithmStatus int expectedAlgorithmStatus) {
|
||||
mLatestEvent.assertHasBeenSet();
|
||||
|
||||
LocationAlgorithmEvent latest = mLatestEvent.getLatest();
|
||||
assertEquals(expectedAlgorithmStatus, latest.getAlgorithmStatus().getStatus());
|
||||
assertNull(latest.getSuggestion());
|
||||
mLatestEvent.commitLatest();
|
||||
}
|
||||
|
||||
void assertEventWithCertainSuggestionReportedAndCommit(TimeZoneProviderEvent event) {
|
||||
// Test coding error if this fails.
|
||||
assertEquals(TimeZoneProviderEvent.EVENT_TYPE_SUGGESTION, event.getType());
|
||||
|
||||
// By definition, the algorithm has to be running to report a suggestion.
|
||||
@DetectionAlgorithmStatus int expectedAlgorithmStatus =
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
TimeZoneProviderSuggestion suggestion = event.getSuggestion();
|
||||
assertSuggestionMadeAndCommit(
|
||||
assertEventWithSuggestionReportedAndCommit(
|
||||
expectedAlgorithmStatus,
|
||||
suggestion.getElapsedRealtimeMillis(),
|
||||
suggestion.getTimeZoneIds());
|
||||
}
|
||||
|
||||
void assertNoSuggestionMade() {
|
||||
mLatestSuggestion.assertHasNotBeenSet();
|
||||
}
|
||||
|
||||
/** Asserts that an uncertain suggestion has been made from the supplied event. */
|
||||
void assertUncertainSuggestionMadeFromEventAndCommit(TimeZoneProviderEvent event) {
|
||||
/**
|
||||
* Asserts that one or more events have been reported, and the most recent contains an
|
||||
* uncertain suggestion matching select details from the supplied provider event.
|
||||
*/
|
||||
void assertEventWithUncertainSuggestionReportedAndCommit(TimeZoneProviderEvent event) {
|
||||
// Test coding error if this fails.
|
||||
assertEquals(TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN, event.getType());
|
||||
|
||||
assertSuggestionMadeAndCommit(event.getCreationElapsedMillis(), null);
|
||||
// By definition, the algorithm has to be running to report a suggestion.
|
||||
@DetectionAlgorithmStatus int expectedAlgorithmStatus =
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
assertEventWithSuggestionReportedAndCommit(
|
||||
expectedAlgorithmStatus, event.getCreationElapsedMillis(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an uncertain suggestion has been made.
|
||||
* Ignores the suggestion's effectiveFromElapsedMillis.
|
||||
* Asserts that one or more events have been reported, and the most recent contains an
|
||||
* uncertain suggestion. Ignores the suggestion's effectiveFromElapsedMillis.
|
||||
*/
|
||||
void assertUncertainSuggestionMadeAndCommit() {
|
||||
void assertEventWithUncertainSuggestionReportedAndCommit() {
|
||||
// By definition, the algorithm has to be running to report a suggestion.
|
||||
@DetectionAlgorithmStatus int expectedAlgorithmStatus =
|
||||
DETECTION_ALGORITHM_STATUS_RUNNING;
|
||||
|
||||
// An "uncertain" suggestion has null time zone IDs.
|
||||
assertSuggestionMadeAndCommit(null, null);
|
||||
assertEventWithSuggestionReportedAndCommit(expectedAlgorithmStatus, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a suggestion has been made and some properties of that suggestion.
|
||||
* When expectedEffectiveFromElapsedMillis is null then its value isn't checked.
|
||||
* Asserts that an event has been reported containing a suggestion and some properties of
|
||||
* that suggestion. When expectedEffectiveFromElapsedMillis is null then its value isn't
|
||||
* checked.
|
||||
*/
|
||||
private void assertSuggestionMadeAndCommit(
|
||||
private void assertEventWithSuggestionReportedAndCommit(
|
||||
@DetectionAlgorithmStatus int expectedAlgorithmStatus,
|
||||
@Nullable @ElapsedRealtimeLong Long expectedEffectiveFromElapsedMillis,
|
||||
@Nullable List<String> expectedZoneIds) {
|
||||
mLatestSuggestion.assertHasBeenSet();
|
||||
mLatestEvent.assertHasBeenSet();
|
||||
|
||||
LocationAlgorithmEvent latestEvent = mLatestEvent.getLatest();
|
||||
assertEquals(expectedAlgorithmStatus, latestEvent.getAlgorithmStatus().getStatus());
|
||||
|
||||
GeolocationTimeZoneSuggestion suggestion = latestEvent.getSuggestion();
|
||||
assertNotNull("Latest event doesn't contain a suggestion: event=" + latestEvent,
|
||||
suggestion);
|
||||
|
||||
if (expectedEffectiveFromElapsedMillis != null) {
|
||||
assertEquals(
|
||||
expectedEffectiveFromElapsedMillis.longValue(),
|
||||
mLatestSuggestion.getLatest().getEffectiveFromElapsedMillis());
|
||||
assertEquals(expectedEffectiveFromElapsedMillis.longValue(),
|
||||
suggestion.getEffectiveFromElapsedMillis());
|
||||
}
|
||||
assertEquals(expectedZoneIds, mLatestSuggestion.getLatest().getZoneIds());
|
||||
mLatestSuggestion.commitLatest();
|
||||
assertEquals(expectedZoneIds, suggestion.getZoneIds());
|
||||
mLatestEvent.commitLatest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user